when passing a 3d array to a function, the memory address of the array suddenly change after performing an fget

huangapple go评论54阅读模式
英文:

when passing a 3d array to a function, the memory address of the array suddenly change after performing an fget

问题

以下是您要翻译的代码部分:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <stddef.h> // for macro NULL

int clear_screen() {
  int pid = fork();
  if (pid == 0) {
    char *newargv[] = { NULL };
    char *newenviron[] = { "TERM=screen" };
    execve("/usr/bin/clear", newargv, newenviron);
  }
  int wait_time = 1;
  int *ptr_wait_time = &wait_time;
  wait(ptr_wait_time);
  return 0;
}

void init (char char_array[5][5][11]) {
  printf("char_array in init is at %p which points to %p\n", &char_array, *char_array);
  printf("char_array[0][0] in init is at %p\n", &char_array[0][0]);
  printf("char_array[0][0][0] in init is at %p\n", &char_array[0][0][0]);
  for (int row = 0; row < 5; row++) {
    for (int col = 0; col < 5; col++) {
      for (int single_char = 0; single_char < 11; single_char++) {
        char_array[row][col][single_char] = ' ';
      }
      char_array[row][col][10] = '\0';
    }
  }
}

void display (char char_array[5][5][11]) {
  printf("\t0\t\t\t\t1\t\t\t\t2\t\t\t\t3\t\t\t\t4\n");
  for (int row = 0; row < 5; row++) {
    printf("%d", row);
    for (int col = 0; col < 5; col++) {
      printf("\t%p[%s]", char_array[row][col], char_array[row][col]);
    }
    printf("\n");
  }
}

int check_if_int (char *user_maybe_int) {
  long result;
  char *endptr;
  result = strtol(user_maybe_int, &endptr, 10);
  if (user_maybe_int[0] != '\n' && *endptr == '\n' && result > -1 && result < 5)  {
    return result;
  }
  else {
    return -1;
  }
}

char *format_user_input (char *user_input) {
  int size_of_input;
  int padding_size;
  char *formated = malloc(11);
  size_of_input = strcspn(user_input, "\n") - 1;
  padding_size = 11 - size_of_input;
  for (int i = 0; i < size_of_input + 1;i ++) {
    formated[i] = user_input[i];
  }
  for (int i = size_of_input + 1; i < 11;i ++) {
    formated[i] = ' ';
  }
  formated[10] = '\0';
  return formated;
}

int insert (char char_array[5][5][11]) {
  printf("char_array in insert is at %p which points to %p\n", &char_array, *char_array);
  printf("char_array[0][0] in insert is at %p and points to %p\n", &char_array[0][0], char_array[0][0]);
  printf("char_array[0][0][0] in insert is at %p\n", &char_array[0][0][0]);
  char user_input_row[2];
  char user_input_col[2];
  printf("did char_array[0][0] changed1? %p points to %p (the answer is : not yet)\n", &char_array[0][0], char_array[0][0]);
  int row;
  printf("did char_array[0][0] changed2? %p points to %p (the answer is : not yet)\n", &char_array[0][0], char_array[0][0]);
  int col;
  printf("did char_array[0][0] changed3? %p points to %p (the answer is : not yet)\n", &char_array[0][0], char_array[0][0]);
  char user_input[11] = "";
  printf("did char_array[0][0] changed4? %p points to %p (the answer is : not yet)\n", &char_array[0][0], char_array[0][0]);
  printf("insert in row : ");
  printf("did char_array[0][0] changed5? %p points to %p (the answer is : not yet)\n", &char_array[0][0], char_array[0][0]);
  fgets(user_input_row, 3, stdin);
  printf("did char_array[0][0] changed6? %p points to %p (the answer is : yes, most of the time)\n", &char_array[0][0], char_array[0][0]);
  row = check_if_int(user_input_row);
  if (row == -1) {
    return 1;
  }
  printf("insert in column : ");
  fgets(user_input_col, 3, stdin);
  col = check_if_int(user_input_col);
  if (col == -1) {
    return 1;
  }
  printf("your input : ");
  fgets(user_input, 12, stdin);
  char *user_input_formated = format_user_input(user_input);
  //actual insert
  printf("User try to insert at %p via char_array[%d][%d]\n", &char_array[row][col], row, col);
  strncpy(char_array[row][col], user_input_formated, 11);
  free(user_input_formated);
  return 0;
}

void start (char char_array[5][5][11]) {
  //clear_screen();
  int insert_res;
  // this function display a grid (memory address + content)
  display(char_array);
  insert_res = insert(char_array);
  if (insert_res != 1) {
    start(char_array);
  }


<details>
<summary>英文:</summary>

as the title mention it : when passing a 3d array to a function, the memory address of the array suddenly change after performing an fget 

the issue occurs in the insert function right after the fgets


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <stddef.h> // for macro NULL

int clear_screen() {
int pid = fork();
if (pid == 0) {
char *newargv[] = { NULL };
char *newenviron[] = { "TERM=screen" };
execve("/usr/bin/clear", newargv, newenviron);
}
int wait_time = 1;
int *ptr_wait_time = &wait_time;
wait(ptr_wait_time);
return 0;
}

void init (char char_array[5][5][11]) {
printf("char_array in init is at %p which points to %p\n", &char_array, *char_array);
printf("char_array[0][0] in init is at %p\n", &char_array[0][0]);
printf("char_array[0][0][0] in init is at %p\n", &char_array[0][0][0]);
for (int row = 0; row < 5; row++) {
for (int col = 0; col < 5; col++) {
for (int single_char = 0; single_char < 11; single_char++) {
char_array[row][col][single_char] = ' ';
}
char_array[row][col][10] = '\0';
}
}
}

void display (char char_array[5][5][11]) {
printf("\t0\t\t\t\t1\t\t\t\t2\t\t\t\t3\t\t\t\t4\n");
for (int row = 0; row < 5; row++) {
printf("%d", row);
for (int col = 0; col < 5; col++) {
printf("\t%p[%s]", char_array[row][col], char_array[row][col]);
}
printf("\n");
}
}

int check_if_int (char *user_maybe_int) {
long result;
char *endptr;
result = strtol(user_maybe_int, &endptr, 10);
if (user_maybe_int[0] != '\n' && *endptr == '\n' && result > -1 && result < 5) {
return result;
}
else {
return -1;
}
}

char *format_user_input (char *user_input) {
int size_of_input;
int padding_size;
char *formated = malloc(11);
size_of_input = strcspn(user_input, "\n") - 1;
padding_size = 11 - size_of_input;
for (int i = 0; i < size_of_input + 1;i ++) {
formated[i] = user_input[i];
}
for (int i = size_of_input + 1; i < 11;i ++) {
formated[i] = ' ';
}
formated[10] = '\0';
return formated;
}

int insert (char char_array[5][5][11]) {
printf("char_array in insert is at %p which points to %p\n", &char_array, *char_array);
printf("char_array[0][0] in insert is at %p and points to %p\n", &char_array[0][0], char_array[0][0]);
printf("char_array[0][0][0] in insert is at %p\n", &char_array[0][0][0]);
char user_input_row[2];
char user_input_col[2];
printf("did char_array[0][0] changed1? %p points to %p (the answer is : not yet)\n", &char_array[0][0], char_array[0][0]);
int row;
printf("did char_array[0][0] changed2? %p points to %p (the answer is : not yet)\n", &char_array[0][0], char_array[0][0]);
int col;
printf("did char_array[0][0] changed3? %p points to %p (the answer is : not yet)\n", &char_array[0][0], char_array[0][0]);
char user_input[11] = "";
printf("did char_array[0][0] changed4? %p points to %p (the answer is : not yet)\n", &char_array[0][0], char_array[0][0]);
printf("insert in row : ");
printf("did char_array[0][0] changed5? %p points to %p (the answer is : not yet)\n", &char_array[0][0], char_array[0][0]);
fgets(user_input_row, 3, stdin);
printf("did char_array[0][0] changed6? %p points to %p (the answer is : yes, most of the time)\n", &char_array[0][0], char_array[0][0]);
row = check_if_int(user_input_row);
if (row == -1) {
return 1;
}
printf("insert in column : ");
fgets(user_input_col, 3, stdin);
col = check_if_int(user_input_col);
if (col == -1) {
return 1;
}
printf("your input : ");
fgets(user_input, 12, stdin);
char *user_input_formated = format_user_input(user_input);
//actual insert
printf("User try to insert at %p via char_array[%d][%d]\n", &char_array[row][col], row, col);
strncpy(char_array[row][col], user_input_formated, 11);
free(user_input_formated);
return 0;
}

void start (char char_array[5][5][11]) {
//clear_screen();
int insert_res;
// this function display a grid (memory address + content)
display(char_array);
insert_res = insert(char_array);
if (insert_res != 1) {
start(char_array);
}
else {
printf("something went wrong on insert!");
exit(1);
}
}

int main () {
// 3d array
// we define 5 x 5 array of arrays of chars (10 chars + null terminator)
// for a visual reprensentation, 2d arrays give columns, 3d arrays add rows
char char_array[5][5][11];
// this function fills each array of chars with "0000000000\0"
init(char_array);
// start the display/insert recursion
start(char_array);
}


as you can see from the multiples printf, I tried to pinpoint the exact moment where the memory address changed, from my understanding, char_array decays to a pointer when passed to this function and the memory address should not change (obviously, i&#39;m missing something because it does change after performing the 1st fgets)

char_array in insert is at 0x7ffc4e60cd70 which points to 0x7ffc4e60cdb0
char_array[0][0] in insert is at 0x7ffc4e60cdb0 and points to 0x7ffc4e60cdb0
char_array[0][0][0] in insert is at 0x7ffc4e60cdb0
did char_array[0][0] changed1? 0x7ffc4e60cdb0 points to 0x7ffc4e60cdb0 (the answer is : not yet)
did char_array[0][0] changed2? 0x7ffc4e60cdb0 points to 0x7ffc4e60cdb0 (the answer is : not yet)
did char_array[0][0] changed3? 0x7ffc4e60cdb0 points to 0x7ffc4e60cdb0 (the answer is : not yet)
did char_array[0][0] changed4? 0x7ffc4e60cdb0 points to 0x7ffc4e60cdb0 (the answer is : not yet)
insert in row : did char_array[0][0] changed5? 0x7ffc4e60cdb0 points to 0x7ffc4e60cdb0 (the answer is : not yet)
0
did char_array[0][0] changed6? 0x7ffc4e60cd00 points to 0x7ffc4e60cd00 (the answer is : yes, most of the time)
did char_array[0][0] changed7? 0x7ffc4e60cd00 points to 0x7ffc4e60cd00 (the answer is : yes, most of the time)
insert in column : did char_array[0][0] changed8? 0x7ffc4e60cd00 points to 0x7ffc4e60cd00 (the answer is : yes, most of the time)
0
did char_array[0][0] changed9? 0x7ffc4e60cd00 points to 0x7ffc4e60cd00 (the answer is : yes, most of the time)
did char_array[0][0] changed10? 0x7ffc4e60cd00 points to 0x7ffc4e60cd00 (the answer is : yes, most of the time)
your input : a
did char_array[0][0] changed11? 0x7ffc4e60cd00 points to 0x7ffc4e60cd00 (the answer is : yes, most of the time)
User try to insert at 0x7ffc4e60cd00 via char_array[0][0]


</details>
# 答案1
**得分**: 0

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main () {
char too_small_buffer[2];
char ok_buffer[3];
printf("在太小的缓冲区中输入一个字符:");
// 如果输入"a"并按回车键:
// 由于fgets没有足够的空间存储'a' '\n' '\0',从这里开始出现未定义的行为
fgets(too_small_buffer, 3, stdin);
printf("存储在太小缓冲区[0]中的十进制数: %d\n", too_small_buffer[0]);
printf("存储在太小缓冲区[1]中的十进制数: %d\n", too_small_buffer[1]);
printf("在ok缓冲区中输入一个字符:");
// 如果上面没有发生缓冲区溢出,这将正常工作
fgets(ok_buffer, 3, stdin);
printf("存储在ok缓冲区[0]中的十进制数: %d\n", ok_buffer[0]);
printf("存储在ok缓冲区[1]中的十进制数: %d\n", ok_buffer[1]);
printf("存储在ok缓冲区[2]中的十进制数: %d\n", ok_buffer[2]);
}


<details>
<summary>英文:</summary>

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main () {
char too_small_buffer[2];
char ok_buffer[3];
printf("enter one char in too small buffer : ");
// if you enter "a" and press enter :
// undefined behavior starts here since fgets
// does not have enough room to store 'a' '\n' '\0'
fgets(too_small_buffer, 3, stdin);
printf("decimal stored in too_small_buffer[0] : %d\n", too_small_buffer[0]);
printf("decimal stored in too_small_buffer[1] : %d\n", too_small_buffer[1]);
printf("enter one char in ok buffer : ");
// this would work fine if there was no buffer overflow above
fgets(ok_buffer, 3, stdin);
printf("decimal stored in ok_buffer[0] : %d\n", ok_buffer[0]);
printf("decimal stored in ok_buffer[1] : %d\n", ok_buffer[1]);
printf("decimal stored in ok_buffer[2] : %d\n", ok_buffer[2]);
}


so fgets reads n-1 (`&quot;a\n&quot;`) and try to add `&#39;\0&#39;` but does not have enough space.
credit to @weather-vane in the comments above who have spotted the issue immediately.
It seems to work fine for this program (the sample program in this answer), but it caused an issue in the initial program.

enter one char in too small buffer : a
decimal stored in too_small_buffer[0] : 97
decimal stored in too_small_buffer[1] : 10
enter one char in ok buffer : a
decimal stored in ok_buffer[0] : 97
decimal stored in ok_buffer[1] : 10
decimal stored in ok_buffer[2] : 0


</details>

huangapple
  • 本文由 发表于 2023年5月13日 18:30:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/76242245.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定