pit of memset

foreword

As a function of memory initialization, memset still has many pitfalls and misunderstandings. Today, I will make a summary of this function.

1. Function


The memset function is widely used in C++ to initialize and set memory. It can quickly set a continuous memory space to a specified value. This function mainly acts on data types such as arrays and structures to make its initial state meet specific requirements.

The simplest call is to clear an array, the code example is as follows:

const int maxn = 1024;
int a[maxn];
memset(a, 0, sizeof(a)); // a[0]=a[1]=a[...]=0;

Here, sizeof(a) = maxn * 4 = 4096;

It means that the 4096 bytes after the first address a of the array are set to 0 ;

In other words, through the memset function, we can initialize all elements of the array a to 0. This operation can greatly improve programming efficiency when dealing with large amounts of data.

2. Efficiency comparison


Directly call the memset interface to clear and call the loop to clear. After a test, it is as follows:

For an array of length 10000000, execute 100 calls;

Because the release version will do various optimizations, the compiler will skip the repeated execution of invalid logic, so it is not easy to create data tests. When studying time efficiency, you should refer to the debug version (of course, the release version must be used when the software is released. Version).

Memset is due to the for loop in terms of time efficiency and code cleanliness. Of course, it also brings some misunderstandings.

3. Summary of misunderstandings

1. Set by byte

The implementation principle of memset is set according to bytes. For example, for byte array char a[100], set all bytes to 5, and then call:

memset(a, 5, sizeof(a));

However, using this method for int b[100] also results in an error:

memset(b, 5, sizeof(b));

Get the value of the element in the b array as 84215045;

why?

We convert this array to binary and get:

Because int occupies 4 bytes, each byte is set to 5, so the final conversion to decimal becomes 84215045;

Similarly, when the type is short (two-byte integer) or long long (eight-byte integer), there will be similar problems. The summary table is as follows:

In the table, only 0 and -1 are normal, because in the binary representation of 0, all bits are 0; in the binary representation of -1, all bits are 1;

In particular, when each byte of the corresponding type of the number to be set is the same number, memset can also be used, for example: 252645135 of int type (hexadecimal representation: 0x0f0f0f0f);

2. Only the lowest byte is valid for the set value

memset(a, 0x05ffffff, sizeof(a));

memset(a, 0xffffff05, sizeof(a));

memset(a, 0xffffff08, sizeof(a));

memset(a, 0x12345678, sizeof(a));

When setting the value, only the lowest byte is used for assignment. In layman's terms, the above four sentences are called, which is equivalent to:

memset(a, 0xff, sizeof(a));

memset(a, 0x05, sizeof(a));

memset(a, 0x08, sizeof(a));

memset(a, 0x78, sizeof(a));

3. The heap memory cannot directly use sizeof to get the first address

In C++, when we allocate memory on the heap, we usually use newthe keyword. When we use sizeofthe operator to operate on a pointer, the size of the pointer itself will be returned, not the size of the memory it points to. Therefore, when we need to initialize or set memory for an array or structure pointer, we need to calculate the memory size correctly. The following are some suggestions and considerations about heap memory and array parameter passing.

  1. When allocating memory on the heap, use new[]the operator to create a dynamic array. This will return a pointer to the first element of the array. For example:
const int maxn = 1024;
int *p = new int[maxn];

  1. When it is necessary to perform initialization or memory setting operations on a dynamic array, use sizeofthe operator to multiply the size of the array element type to obtain the correct memory size. For example:
const int maxn = 1024;
int *p = new int[maxn];
memset(p, 0, maxn * sizeof(int));

4. The parameter group cannot be directly sizeof to get the first address

  1. When passing an array as a function argument, the array name degenerates into a pointer. Therefore, inside the function, we cannot sizeofdirectly get the array size using the operator. Instead, we need to pass the array size as a function parameter, or use some other method to get the array size. For example:
void fun(int a[], int size) {
    memset(a, 0, size * sizeof(int));
}

  1. When the structure pointer is passed as a function parameter, you also need to pay attention to this problem. A pointer to a structure degenerates into a pointer, so we cannot use sizeofthe operator to get the size of the structure directly. The solution is similar to an array, pass the size of the structure as a function parameter, or use other methods to get the size of the structure. For example:
void fun(MyStruct *s, int size) {
    memset(s, 0, size * sizeof(MyStruct));
}

In summary, when dealing with heap memory and array parameter passing, we need to pay attention to the difference between pointers and array names, and use the correct method to get the memory size to avoid errors and potential memory problems.

This article is published by mdnice multi-platform

Guess you like

Origin blog.csdn.net/m0_67759533/article/details/131776678