从 C 中的 fscanf() 初始化时数组值不一致
Inconsistent array values when initialized from fscanf() in C
如果 main() 中的多维数组是从这样的函数指针初始化的:
#include <stdio.h>
void arrayfunction(int (*n)[3][3])
{
(*n)[0][2]=7;
printf("Function output: %i\n", *n[0][2]);
}
main()
{
int y[3][3];
arrayfunction(&y);
printf("Main output: %i \n",y[0][2]);
return(0);
}
然后 main() 中的数组将保存正确的值,但 arrayfunction() 中的指针的输出将不会:
Function output: 4195805
Main output: 7
但是,如果函数通过fscanf()通过函数指针初始化main()中的数组:
#include <stdio.h>
void readSchedule(int (*s)[3][3]){
FILE *schedule;
schedule=fopen("/var/schedule.conf","r");
fscanf(schedule,"[%i,%i,%i,%i]\n",s[0][0], s[0][1], s[0][2], s[0][3]);
fclose(schedule);
printf("Function output value: %i\n",*s[0][2]);
}
main()
{
int x[3][3];
readSchedule(&x);
printf("Main output value: %i\n ",x[0][2]);
return(0);
}
然后取反,函数局部的指针会输出正确的值,但它在main()中指向的数组不会:
Function output value: 7
Main output value: 0
为什么正确的值在第一个例子中只出现在 main() 局部数组中,而在第二个例子中只出现在函数局部指针中?
检查运算符优先级并注意在 arrayFunction
中使用 n
的两行中的区别
(*n)[0][2]=7;
printf("Function output: %i\n", *n[0][2]);
括号在这里很关键。 []
运算符的优先级高于 *
(http://en.cppreference.com/w/cpp/language/operator_precedence)。如果您在 printf 行中添加括号,您将看到您所期望的结果。
fscanf
示例中或多或少发生了同样的事情。编译器将 s[0][0]
视为指向 int 的指针(像这样 *(s[0][0])),因此数据被写入未定义的区域。
如果您使用像 valgrind 这样的内存调试程序,您会看到大量错误。
第一个例子中的问题在函数内的 printf 语句中指向数组参数的指针的语法中通过更改优先级解决了:
printf("Function output: %i\n", *n[0][2]);
到
printf("Function output: %i\n", (*n)[0][2]);
在第二个示例中,fscanf() 显然是将值直接填充到 *s[][] 中,而不是间接初始化 *s[][] 指向的 main() 中的数组。所以不是这个:
fscanf(schedule,"[%i,%i,%i,%i]\n",s[0][0], s[0][1], s[0][2], s[0][3]);
语法必须是这样的:
fscanf(schedule,"[%i,%i,%i,%i]\n",&(*s)[0][0], &(*s)[0][1], &(*s)[0][2], &(*s)[0][3]);
为了到达 *s[][] 并将值放在 y[][] 中。
如果 main() 中的多维数组是从这样的函数指针初始化的:
#include <stdio.h>
void arrayfunction(int (*n)[3][3])
{
(*n)[0][2]=7;
printf("Function output: %i\n", *n[0][2]);
}
main()
{
int y[3][3];
arrayfunction(&y);
printf("Main output: %i \n",y[0][2]);
return(0);
}
然后 main() 中的数组将保存正确的值,但 arrayfunction() 中的指针的输出将不会:
Function output: 4195805
Main output: 7
但是,如果函数通过fscanf()通过函数指针初始化main()中的数组:
#include <stdio.h>
void readSchedule(int (*s)[3][3]){
FILE *schedule;
schedule=fopen("/var/schedule.conf","r");
fscanf(schedule,"[%i,%i,%i,%i]\n",s[0][0], s[0][1], s[0][2], s[0][3]);
fclose(schedule);
printf("Function output value: %i\n",*s[0][2]);
}
main()
{
int x[3][3];
readSchedule(&x);
printf("Main output value: %i\n ",x[0][2]);
return(0);
}
然后取反,函数局部的指针会输出正确的值,但它在main()中指向的数组不会:
Function output value: 7
Main output value: 0
为什么正确的值在第一个例子中只出现在 main() 局部数组中,而在第二个例子中只出现在函数局部指针中?
检查运算符优先级并注意在 arrayFunction
中使用n
的两行中的区别
(*n)[0][2]=7;
printf("Function output: %i\n", *n[0][2]);
括号在这里很关键。 []
运算符的优先级高于 *
(http://en.cppreference.com/w/cpp/language/operator_precedence)。如果您在 printf 行中添加括号,您将看到您所期望的结果。
fscanf
示例中或多或少发生了同样的事情。编译器将 s[0][0]
视为指向 int 的指针(像这样 *(s[0][0])),因此数据被写入未定义的区域。
如果您使用像 valgrind 这样的内存调试程序,您会看到大量错误。
第一个例子中的问题在函数内的 printf 语句中指向数组参数的指针的语法中通过更改优先级解决了:
printf("Function output: %i\n", *n[0][2]);
到
printf("Function output: %i\n", (*n)[0][2]);
在第二个示例中,fscanf() 显然是将值直接填充到 *s[][] 中,而不是间接初始化 *s[][] 指向的 main() 中的数组。所以不是这个:
fscanf(schedule,"[%i,%i,%i,%i]\n",s[0][0], s[0][1], s[0][2], s[0][3]);
语法必须是这样的:
fscanf(schedule,"[%i,%i,%i,%i]\n",&(*s)[0][0], &(*s)[0][1], &(*s)[0][2], &(*s)[0][3]);
为了到达 *s[][] 并将值放在 y[][] 中。