在C语言中修改函数内部的数组

9
// test.txt
50
13
124

-

void hi ( int *b, FILE *pfile ) {

    rewind ( pfile );
    int i;
    for( i = 0 ; i < 3 ; i++ ) {
         fscanf ( pfile, "%d", &b[i] );
    }
}

int main ( void ) {

    FILE *fp = fopen ( "test.txt", "r" );
    int a[10];  //putting extra size for test.

    hi ( &a[0], fp );   
    printf("%d,%d,%d\n", a[0], a[1], a[2]);

    fclose ( fp );
    return 0;
}

我正在尝试理解指针和数组的关系。在测试上述代码时,我注意到当将不同的索引值(例如将&a[0]改为&a[1])传递给函数hi(&a[0], fp)hi(&a[1], fp)时,会得到不同的结果。

// [ hi ( &a[0], fp ) ] 的结果 // [ hi ( &a[1], fp ) ] 的结果 50,13,124 junk#,50,13 .

对于这个结果,我感到非常困惑,因为在函数hi中,我明确指定了从i = 0开始存储数组的值,这应该意味着它从a[0]开始存储。但是似乎用1代替0会把值向一边移动。为什么会发生这种情况呢?


1
&b[i] 就是 b + i。如果你传入 &a[0](对于指针来说与 a 相同),那么它就变成了 a + i。如果你传入 &a[1],也就是 a + 1,那么它就变成了 a + 1 + i - Ry-
3个回答

6
如果您将&看作是一个操作符,它可以像-改变数字的符号一样作用于单个项目,那么这可能更容易理解。在这种情况下,&获取您提供的任何内容的地址。在&a[0]的情况下,您正在获取a[0]的地址。在&a[1]的情况下,您获取a[1]的地址。换句话说,您获取数组的不同元素的地址。因此,在函数中,b包含您传递给它的地址。就函数而言,您传递的是数组的“第一个”元素。它不知道任何先前的元素。

哇,我现在明白了。谢谢你提供这么简单易懂的答案。 - ChewChew
@ChewChew 很高兴我能帮到你。请阅读当有人回答我的问题时我该怎么做? - Code-Apprentice

4
您并没有“放置不同大小的元素”,而是提供了指向数组中第一个元素,然后是第二个元素的指针。
因为在第二种情况下,您提供了指向第二个元素的指针,并尝试读取10个元素(从第二个位置开始),但仅有9个有效元素,当从第二个元素开始时,您正在读取不在数组中的内存。

4
在您的第二个示例中存在未定义的行为。您传递了数组的第二个元素的地址。然后,您scanf了所有10个元素。但是由于您将第二个元素的地址作为初始元素传递,最后一个scanf会写入超出数组范围的元素 - 这是一个错误。
我建议如果您要操作数组的多个元素,请同时传递数组的大小。
#define ARRAYSIZE(x)   (sizeof(x) / sizeof(x[0]))

void hi ( int *b, FILE *pfile, size_t size ) {

    rewind ( pfile );
    int i;
    for( i = 0 ; i < size ; i++ ) {
         fscanf ( pfile, "%d", &b[i] );
    }
}

以及调用

hi ( a, fp, ARRAYSIZE(a));   

或者

hi ( &a[0], fp, ARRAYSIZE(a));   

很好的建议。传递数组大小是一个好习惯。只要小心使用ARRAYSIZE宏,因为它在&a[1]时将无法给出正确的结果。 - Code-Apprentice
宏的参数必须是数组本身,而不是元素的地址或元素。 - 0___________
确切地说,hi(&a[1], fp, ARRAYSIZE(&a[1]))hi(&a[1], fp, ARRAYSIZE(a))都是不正确的。你可以通过解释这一点使你的答案更完整,因为原始问题是关于&a[0]&a[1]之间的区别。 - Code-Apprentice

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接