为什么memset在功能上会有所不同?

时间:2019-10-22 00:47:18

标签: c arrays function c99 memset

当我从函数内部调用memset时,我试图弄清楚为什么memset不起作用。 当然,我可以使用for循环来重置所有值,但是我在这里学习的是,这件事使我没有任何解释。

/* First source code */
#include <stdio.h>
#include <string.h>

int main(void) {
    int i, j, num;

    printf("Digit a number :");
    scanf("%d", &num);

    int magic[num][num];

    printf("First\n");
    for(i = 0; i < num; ++i) {
        for(j = 0; j < num; ++j) {
            printf("%4d", magic[i][j]);
        }
        printf("\n\n");
    }

    memset(magic, 0, sizeof(magic));

    printf("Before\n");
    for(i = 0; i < num; ++i) {
        for(j = 0; j < num; ++j) {
            printf("%4d", magic[i][j]);
        }
        printf("\n\n");
    }

    return 0;
}

/* Second source code */
#include <stdio.h>
#include <string.h>

void create_magic_square(int n, int magic_square[][n]);
void print_magic_square(int n, int magic_square[][n]);

int main(void) {
    int num;
    printf("Digit a number :");
    scanf("%d", &num);
    int magic[num][num];
    create_magic_square(num, magic);
    return 0;
}

void create_magic_square(int n, int magic_square[][n]) {
    int i, j;

    printf("First\n");
    for(i = 0; i < n; ++i) {
        for(j = 0; j < n; ++j) {
            printf("%4d", magic_square[i][j]);
        }
        printf("\n\n");
    }

    //memset(magic_square, 0, n * sizeof(magic_square[0]));
    memset(magic_square, 0, sizeof(magic_square));

    printf("Before\n");
    for(i = 0; i < n; ++i) {
        for(j = 0; j < n; ++j) {
            printf("%4d", magic_square[i][j]);
        }
        printf("\n\n");
    }
}

在第二个代码(带有函数)中,我应该把这一行: memset(magic_square,0,n * sizeof(magic_square [0])); 用于清除二维数组,同时具有: memset(magic_square,0,sizeof(magic_square)); 不起作用。为什么会这样?

1 个答案:

答案 0 :(得分:5)

当您将数组传递给C语言中的函数时,即使您在函数原型中指定了数组类型,它们也会衰减为指向数组中第一个元素的指针, (a)。因此,sizeof将为您提供指针的大小,而不是数组的大小。

常见的做法是将数组大小与数组一起传递(可能是size_t),并使用 that 编织魔术,例如:

int zeroArray(void *address, size_t sz) { // void* makes it clear
    memset(address, 0, sz);               // but int thing[][] would be same.
}
:
int xyzzy[42][7];
zeroArray(xyzzy, sizeof(xyzzy));

但是,您已经已经向当前函数传递了足够的信息来执行此操作,特别是n。您应该能够使用它来为sizeof运算符形成一个类型(可以使用变量一个类型),它将满足您的需要:

memset(magic_square, 0, sizeof(int[n][n]));

(a)C11部分下的最新标准6.3.2.1 Lvalues, arrays, and function designators /3中涵盖:

  

除非它是sizeof运算符,_Alignof运算符或一元&运算符的操作数,或者是用于初始化数组的字符串文字,将类型为“数组类型”的表达式转换为类型为“指针类型”的表达式,该表达式指向数组对象的初始元素,而不是左值。

尽管您使用了c99标签,但我还是引用了该标准的 latest 迭代,唯一的区别是C99标准没有提及Alignof,因为它不存在在那个迭代中。除此之外,报价是相同的。

这可以追溯到,甚至可以追溯到K&R第一版5.3 Pointers and arrays

  

实际上,编译器将对数组的引用转换为指向数组开头的指针。