如何在C语言中使用memset函数对二维数组的成员进行初始化?

19

我想知道如何在C语言中的二维数组中使用memset()函数。

我不想在这个数组中遇到任何垃圾问题。我该如何初始化这个数组?

有人可以解释一下如何实现吗?


6
答案取决于数组是使用栈内存还是堆内存定义的。 - R Sahu
2
无论是在堆栈还是堆上,使用memset,就像Op请求的那样,没有任何区别。 - ash
2
当然,使用memset并不总是最佳选择。一个解决方法是,如果正在使用malloc(),尝试使用calloc()代替。 - ash
1
如果你需要使用memset并想要确定数组的大小,请发布一些展示如何分配数组的代码,以便获得帮助。 - ash
这是我的初始化代码,定义了一个二维数组。我需要创建一个二维动态数组,因此我以这种方式声明它。int **matrix; int **back; - Fisol Rasel
6个回答

30

如果您的2D数组具有静态储存期,则默认初始化为零,即将数组的所有成员设置为零。

如果2D数组具有自动存储期,则可以使用数组初始化列表将所有成员设置为零。

int arr[10][20] = {0};  // easier way
// this does the same
memset(arr, 0, sizeof arr); 
如果您动态分配数组,那么您可以使用memset将所有字节设置为零。
int *arr = malloc((10*20) * (sizeof *arr));
// check arr for NULL

// arr --> pointer to the buffer to be set to 0
// 0 --> value the bytes should be set to
// (10*20*) * (sizeof *arr) --> number of bytes to be set 
memset(arr, 0, (10*20*) * (sizeof *arr));

1
这里,终于有一个使用memset的答案。要使用memset,找到数组的起始地址(很容易 - 它是数组变量的值,或者如果您更喜欢更明确的元素地址,则为所有索引= 0的元素的地址)。然后找到数组的长度;这可能会更棘手。一旦两者都知道了,就调用memset。 - ash
Ajay,更像是“如果2D数组具有自动或静态存储期,则可以使用数组初始化列表将所有成员设置为零。” - chux - Reinstate Monica
(a*b) * (sizeof *arr)改成sizeof *arr * a * b)可以避免a*b溢出,因为sizeof *arr * a使用size_ta的最宽的类型进行计算。 - chux - Reinstate Monica

5
如果您有一个整数数组,并想要显式使用memset:
int array[M][N];

声明时不需要使用 { 0 } 进行初始化。

就这样。

memset(array,0,M*N*sizeof (int));

所有上述都是正确的,因为为了获得数组的正确大小,必须先对数组进行初始化。而数组会向指针一级衰变。

2
memset(array,0,M*N*sizeof(int));改为memset(array,0,sizeof(int)*M*N);以防止M*N的数学溢出。 - chux - Reinstate Monica
1
甚至更好的写法是 memset(array, 0, sizeof array); - chux - Reinstate Monica
我对你的第二条评论@chux - Reinstate Monica不太确定。需要查找更多有关标准化版本的信息以比较是否存在差异。此外,在第一条评论中,我认为显式声明数据类型会首先被读取。如果由于乘法操作而发生溢出,我相信我们无论如何都会遇到问题。但是,我还是给你点赞,因为你考虑得很周全。 - Vor Toumpa
1
int array[M][N]M*N*sizeof(int)非常大时,可能会发生溢出。考虑到M,N都是0x10000,int/unsigned为32位,size_t为64位。M*N会导致int/unsigned数学运算溢出--> UB。 - chux - Reinstate Monica

2
以下是一个重要的观点,需要理解当您想使用memset()时:
memset() 允许您将给定值设置为内存中的单个字节,而不是整个内存。
int arr[2][3] = { 1,2,3,4,5,6 }; //  1   2   3   4 ...  6

// Works as you expected
memset(arr,  0, sizeof arr);     //  0   0   0   0 ...  0
memset(arr, -1, sizeof arr);     // -1  -1  -1  -1 ... -1

// Looks strange !!! - Explanation below
memset(arr,  1, sizeof arr);     // 16843009 16843009 .... 16843009

memset(arr, 1, sizeof arr);会将内存中每个字节都设置为1

例如在32位系统中:

00000001 00000001 00000001 00000001 = 0x01010101 = 16843009 != 1 (0x00000001)

同样地
memset(arr, -1, sizeof arr);     // -1  -1  -1  -1 ... -1

将内存中的所有字节都重置为-1(1111 1111)。

11111111 11111111 11111111 11111111 = 0xFFFFFFFF = -1

1

初始化在C语言中是一个具体的概念。

初始化发生在定义时而不是之后。

int a[M][N] = { 0 };  // Initialization

int b[M][N];
memset(b, 0, sizeof b);  // Assignment

OP评论:

这是我定义二维数组的初始化代码,我需要创建二维动态数组,因此我以这种方式声明。 int **matrix; int **back;

在这种情况下,matrix不是2D数组,而是指向指针的指针。

指针不是数组。数组也不是指针。

要分配一个指向以零填充的int数据的指针数组:

int **matrix = malloc(sizeof matrix[0] * M);
if (matrix) {
  for (size_t m = 0; m < M; M++) {
    matrix[m] = calloc(N, sizeof matrix[m][0]);
  }
}

如果必须使用 memset()
    // matrix[m] = calloc(N, sizeof matrix[m][0]);
    matrix[m] = malloc(sizeof matrix[m][0] * N);
    memset(matrix[m], 0, sizeof matrix[m][0] * N); 

1

简单来说:

int array[10][10]={0};

这将会将你的数组成员全部初始化为0。


C99标准6.7.8.21:

如果大括号中的初始化值少于聚合体中的元素或成员数量,或者用于初始化已知大小数组的字符串文字中的字符数少于数组中的元素数,则聚合体的其余部分将被隐式初始化为具有静态存储期的对象相同。


1
Op特别要求使用memset。 - ash
2
@ash:我认为楼主并不理解他/她所需的语义。在下一句话中,他/她引用了期望的功能,这可以通过使用上述方法简单地实现,没有必要使用memset。而且,如果要挑剔的话,楼主说“初始化”,从技术上讲,使用memset并不能“初始化”任何东西,它只是将内存设置为0 - Alok Save
@ash:感谢您的评论。我们的目标是通过尝试将答案映射到“OP需要”的内容,而不是“OP要求”的内容,来提供最好的答案。并不是所有的OP都能清楚地表达前者,所以我会让OP澄清需求。另外需要澄清的是,在任何情况下,“memset”都不会初始化任何东西。在技术术语上,初始化意味着在单个步骤中创建具有特定值的对象,“memset”永远无法实现这一点。 - Alok Save
1
我明白了。只是想让你知道 - 如果我正在寻找与 Op 所问的完全相同的内容,即如何在多维数组上使用 memset,并找到了你的答案,无论你有多少声望或年份都没有用。很抱歉你觉得声望和时间可以取代所有其他判断或有效输入。 - ash
1
@AlokSave 就像 ash 告诉你的那样,我看到了你的回答,因为我想要对一个二维数组进行 memset 操作,而不是初始化它。 - Max13
显示剩余6条评论

1
Alok Save的回答是最好的,因为它适用于任何类型的数组。您还可以稍后重置数组,例如:
{
    T const blank[10][10] = { 0 };
    STATIC_ASSERT(sizeof blank == sizeof array);
    memcpy(&array, &blank, sizeof array);
}

这适用于所有类型。
如果您真的想使用 memset,那么可以这样做:
memset(&array, 0, sizeof array);

如果您只有数组的第一个元素的指针,那么:
memset(ptr, 0, number_of_elements * sizeof *ptr);

然而,这些版本都将所有字节设置为零,这可能不是浮点类型和指针类型的有效表示。

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