简体   繁体   中英

I was studying with a friend about the C language dynamic allocation malloc realloc. But there was a question. I think about Memory Set

This code writes additional data by increasing the size by 3 when it reaches the size (cur) allocated to the array after dynamically allocating 5 arrays.

The code I wrote is below.

#define _CRT_SECURE_NO_WARNINGS
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

int main() {

    int i = 0;
    int* arr = (int*)malloc(sizeof(int) * 5);
    int curs = sizeof(arr) * 5 / sizeof(int);

    while (1) {

        printf("Input Num : (-1 input exit): ");
        scanf("%d", &arr[i]);
        if (arr[i] == -1)
            break;

        if ((i + 1) == curs) {
            arr = (int*)realloc(arr, sizeof(int) * (3 + curs));
            printf("Add Allocation Arr!\n");
            curs += 3;
        }
        i++;
    }
                printf(" Arr : ");

                for (int j = 0; j < i; j++) {
                    printf("%d ", arr[j]);
                }
    free(arr);
    return 0;

}

When I entered the data as below, it worked fine.

Input Data(Input -1 Exit): 1

Input Data(Input -1 Exit): 2

Input Data(Input -1 Exit): 3

Input Data(Input -1 Exit): 4

Input Data(Input -1 Exit): 5

Add Allocation Arr!

Input Data(Input -1 Exit): 1

Input Data(Input -1 Exit): 2

Input Data(Input -1 Exit): 3

Add Allocation Arr!

Input Data(Input -1 Exit): -1

Arr: 1 2 3 4 5 1 2 3

Here, a friend tried one thing.

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {

    int* arr = (int*)malloc(sizeof(int) * 5);
    int i = 0;
    int curs = sizeof(arr) * 5 / sizeof(int);

    while (1) {
        printf("Input Data(Input -1 Exit): ");
        scanf("%d", &arr[i]);
        if (arr[i] != -1) {
            if ((i + 1) == curs) {
                printf("Add Allocation Arr!\n");
                curs += 3;
                i++; // ★<-- don't use realloc, just i++
                continue;
            }
            else {
                i++;
                continue;
            }
        }
        else {
            printf("Arr: ");
            for (int j = 0; j < i; j++) {
                printf("%d ", arr[j]);
            }
            break;
        }
    }

    free(arr);
    return 0;
}

If you look at the ★ in the comment above, you can see that the array is accessed by simply increasing i without realloc.

When I entered the data as below, it worked fine.

Input Data(Input -1 Exit): 1

Input Data(Input -1 Exit): 2

Input Data(Input -1 Exit): 3

Input Data(Input -1 Exit): 4

Input Data(Input -1 Exit): 5

Add Allocation Arr!

Input Data(Input -1 Exit): 1

Input Data(Input -1 Exit): 2

Input Data(Input -1 Exit): 3

Add Allocation Arr!

Input Data(Input -1 Exit): 1

Input Data(Input -1 Exit): 2

Input Data(Input -1 Exit): 3

Add Allocation Arr!

Input Data(Input -1 Exit): -1

Arr: 1 2 3 4 5 1 2 3 1 2 3

Why is this running?

I was curious, and I used the code below to check the memory status.

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {

    int* arr = (int*)malloc(sizeof(int) * 5);
    int i = 0;
    int curs = sizeof(arr) * 5 / sizeof(int);
    for (i = 0; i < 20; i++)
    {
        printf("%d ", arr[i]);
    }
    free(arr);
    return 0;
}

The execution result is as follows.

-842150451 -842150451 -842150451 -842150451 -842150451 -33686019 7077988 108 -969574923 134254852 12127432 12077032 12127440 12077040 12127448 12077048 2076049408 2076489216 1527808 4456514

I wanted to access it using only the 5 allocated memory. It was expected that an error would occur after accessing the arr[4] index, but that result was printed. It's very confusing.

The C language doesn't do any kind of bounds checking on arrays, trusting the programmer to do the right thing. That's part of what makes it fast. But that also means that if you don't do the right thing, there are no guarantees that your program will work as expected.

What you are seeing is a manifestation of undefined behavior . When you read/write past the end of an array, the program could crash, it could output strange results, or in could (as in this case) appear to work properly. Worse, the way undefined behavior manifests could change by making a seemingly unrelated change to your code such as an unused local variable or a call to printf for debugging.

Just because the program could crash doesn't mean it will .

This is curious:

int curs = sizeof(arr) * 5 / sizeof(int);

If this is trying to compute the number of elements in the array, then it's incorrect (and redundant, as you already know you've set aside space for 5 elements). sizeof(arr) gives you the size of a pointer to int , not the size of an int . Honestly, at this point it just needs to be

int curs = 5;

The general protocol for allocating and re-allocating memory looks like this:

/**
 * Define some symbolic constants for the initial size
 * and the number of elements to add.
 */
#define START_SIZE 5
#define EXTENT     3

/**
 * Track the number of elements that have been allocated.
 * Using size_t instead of int since that’s what’s
 * usually used to represent sizes 
 */
size_t size = START_SIZE;

/**
 * Unless you’re compiling this as C++ or using an
 * *ancient* K&R C implementation, you should not
 * cast the result of malloc, calloc, or realloc
 */
int *arr = malloc( sizeof *arr * size ); // sizeof *arr == sizeof (int)

/**
 * ALWAYS check the result of malloc, calloc,
 * and realloc.    
 */
if ( !arr )
{
  /**
   * Handle initial allocation failure here.  In
   * this case we just print an error message and exit.
   */
  fputs( "Initial allocation failure, exiting", stderr );
  exit( 0 );
}

size_t i = 0;

/**
 * In this example, "done” is just a placeholder for whatever
 * logic you use to determine when to end the loop.
 */
while ( !done ) 
{
  if ( i == size ) 
  {
    /**
     * We’ve run out of space in the array, so we
     * need to extend it with realloc.
     *
     * Since realloc can return NULL if it can’t satisfy
     * the request, ALWAYS assign the result to a temporary
     * variable, otherwise you will lose your reference
     * to the previously-allocated memory.
     */
    int *tmp = realloc( arr, sizeof *arr * (size + EXTENT) );
    if ( !tmp )
    {
      /**
       * The realloc operation failed.  How you handle this
       * depends on the needs of you program, but realize
       * that the previously-allocated memory is still
       * there and that arr still points to it.  In this
       * case, we’ll just print an error message and exit
       * the loop.
       */
      fputs( "Realloc failed, not accepting any more input", stderr );
      done = 1;
      continue;
    }
    else
    {
      size += 3;
      arr = tmp;
    }
  }
  /**
   * The following line is just a placeholder for whatever
   * logic you use to obtain the next value for the array.
   * We’ll assume it sets the "done" condition appropriately
   * and doesn’t increment i unnecessarily.
   */
  arr[i++] = new_value();
}
    

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