简体   繁体   中英

Why memset init partially?

I'm trying to init a int **a with 0 by memset . But the result is some item is not zero.
Source code

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>

int main()
{
    int aSize = 3;
    int **a = (int **)malloc(sizeof(int *)*aSize);
    for (int i=0; i<aSize; i++) {
        a[i]=(int *)malloc(sizeof(int)*aSize);
    }

    memset(a[0], 0, aSize*aSize*sizeof(int));

    for (int i=0; i<aSize; i++) {
        for (int j=0; j<aSize; j++) {
            printf("%d ", a[i][j]);
        }
        printf("\n");
    }
}

Output

0 0 0 
0 0 0 
0 1610612736 0

Update 1

I'm trying to malloc contiugous in two ways as suggested. But in method 2 a exception thrown when init array.

#include <stdio.h>
#include <stdlib.h>
#include <strings.h> // memset header changed
// method 1
int **a = malloc(sizeof(int *)*aSize);
for (int i=0; i<aSize; i++) {
    a[i]=malloc(sizeof(int)*aSize);
    memset(a[i], 0, aSize*sizeof(int));
}

for (int i=0; i<aSize; i++) {
    for (int j=0; j<aSize; j++) {
        printf("%d ", a[i][j]);
    }
    printf("\n");
}

for (int i=0; i<aSize; i++) {
    free(a[i]);
}

free(a);

// method 2
a = malloc(sizeof(int *)*aSize + sizeof(int)*aSize);
memset(a[0], 0, aSize*aSize*sizeof(int)); // Exception: EXC_BAD_ACCESS (code=1, address=0x1c)

This cannot possibly work other than by amazing fluke:

memset(a[0], 0, aSize*aSize*sizeof(int));

You have simulated a multi-dimensional array by allocating a vector of pointers to separately allocated rows. But in the above expression, you're assuming that the memory is linear (allocated all in one piece). The memset writes beyond the end of the a[0] row, causing undefined behavior.

The correct approach is to iterate over the array of pointers, and individually memset each row:

for (i = 0; i < aSize; i++)
   memset(a[i], 0, aSize * sizeof a[i]);

This memset action can be hoisted into the original loop which allocates the rows; moreover, calloc can be used instead of malloc to make the memset unnecessary. (The C language requires that an all-zero bit memory pattern produces values of zero when interpreted as a numeric type such as int or double , so initializing numeric arrays to zero with calloc is type safe and portable.)

Also, there is no <memory.h> header in standard C. The malloc function has been declared in <stdlib.h> since before C was first standardized in 1989.

Your memset line assumes that the array of pointers created in your first for loop point to contiguous memory - that is, you assume that, for example, a[1] will point to the memory location immediately following the buffer pointed to by a[0] .

However, there is no guarantee that this will be the case, As it happens, in some of your cases this is true but, ultimately, working on this assumption will cause Undefined Behaviour !

To correct the problem, you should initialize each memory buffer separately; the simplest way would be to do it as your create each one:

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>

int main()
{
    int aSize = 3;
    int **a = (int **)malloc(sizeof(int *)*aSize);
    for (int i=0; i<aSize; i++) {
        a[i]=(int *)malloc(sizeof(int)*aSize);
         memset(a[i], 0, aSize*sizeof(int)); // Set each buffer to all zeros here!
    }

//  memset(a[0], 0, aSize*aSize*sizeof(int)); // This will cause undefined behaviour

    for (int i=0; i<aSize; i++) {
        for (int j=0; j<aSize; j++) {
            printf("%d ", a[i][j]);
        }
        printf("\n");
    }
}

Feel free to ask for further clarification and/or explanation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM