为什么 memset 在功能上的工作方式不同?

Why does memset work differently in functions?

我想弄清楚为什么当我从函数内部调用 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)); 不起作用。为什么会这样?

当您将数组传递给 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) 涵盖在最新标准 C116.3.2.1 Lvalues, arrays, and function designators /3:

部分

Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, or is a string literal used to initialize an array, an expression that has type "array of type" is converted to an expression with type "pointer to type" that points to the initial element of the array object and is not an lvalue.

尽管有你的 c99 标记,我还是引用了标准的 最新 迭代,唯一的区别是 C99 标准没有提到 Alignof因为它在那个迭代中不存在。除此之外,引用是相同的。

方式 倒退,甚至回到 K&R 第一版,5.3 Pointers and arrays:

In fact, a reference to an array is converted by the compiler to a pointer to the beginning of the array.