Problems updating pointer doing realloc using a structure

Anonymoose

I'm trying to create a self-expanding array of a structure. I saw the questions here, here and here but the answers didn't seem to apply to my situation.

I have had pretty good luck using this technique using an array of strings, but using a structure doesn't work. Below is the code:

//  SO1.h
//
#pragma once

typedef struct {
    int tag;
    int type;
}structure;

void addElement(structure* Tkn_A, const int Tag);

void listArray();

Here is the C code.

// SO1.cpp : This file contains the 'main' function. Program execution begins and ends there.
//

#include "stdio.h"
#include "malloc.h"
#include "SO1.h"

const int   ARRAY_INITIAL_SIZE = 2;
const int   ARRAY_ADDITIONAL_SIZE = ARRAY_INITIAL_SIZE / 2;
structure* userArray;
size_t userArrayLength = -1;
size_t userArrayAvailable = ARRAY_INITIAL_SIZE;

int main()
{
    userArray = (structure*)malloc(userArrayAvailable * sizeof(structure));
    printf(" orgarrptr=%p\n", userArray);

    addElement(userArray, 13);
    addElement(userArray, 14);
    addElement(userArray, 15);
    addElement(userArray, 16);
    addElement(userArray, 17);
    addElement(userArray, 18);
    addElement(userArray, 19);
    addElement(userArray, 20);
    addElement(userArray, 21);
    addElement(userArray, 22);
    addElement(userArray, 23);
    addElement(userArray, 24);
    addElement(userArray, 25);
}

void addElement(structure* userArray, const int tag)
{
    userArrayLength++;
    if (userArrayLength > userArrayAvailable) {
        userArrayAvailable += ARRAY_ADDITIONAL_SIZE;
        structure* originalUserArrayPtr = userArray;
        printf(" orgarrptr=%p\n", originalUserArrayPtr);
        userArray = (structure*)realloc(userArray, userArrayAvailable * sizeof(structure));
        printf(" newarrptr=%p\n", userArray);
        if (originalUserArrayPtr != userArray) {
            printf("pointers different\n");
        }
    }
    userArray[userArrayLength].tag = tag;
    userArray[userArrayLength].type = 1;

    printf("%2d   %d\n\n", userArray[userArrayLength].tag,
        userArray[userArrayLength].type);

    listArray();
}

void listArray()
{
    for (size_t i = 0; i <= userArrayLength; i++) {
        printf("%2d   %d\n", userArray[i].tag,
            userArray[i].type);
    }
}

When the program doesn't complete normally, I get the following error on the line doing the realloc:

Debug Assertion Failed!

File: minkernel\crts\ucrt\src\appcrt\heap.cpp
Line: 604

Expression _CrtIsValidHeapPointer(block)

This happens when the realloc comes up with a different pointer than the original with a new length. But the next time I look at the pointer, it still has the value of the old pointer. Below is the output of one run:

:
:
:
13   1
14   1
-842150451   -842150451
-842150451   -842150451
-842150451   -842150451
-842150451   -842150451
-842150451   -842150451
20   1
 orgarrptr=015C79E0
 newarrptr=015C79E0
21   1

13   1
14   1
-842150451   -842150451
-842150451   -842150451
-842150451   -842150451
-842150451   -842150451
-842150451   -842150451
-842150451   -842150451
21   1
 orgarrptr=015C79E0
 newarrptr=015C5F58        <===  new pointer
pointers different
22   1

13   1
14   1
-842150451   -842150451
-842150451   -842150451
-842150451   -842150451
-842150451   -842150451
-842150451   -842150451
-842150451   -842150451
21   1
-1863261150   134281082
 orgarrptr=015C79E0        <===  original pointer


exited with code 3.

Does anyone know what would cause this problem? TIA.

Sorry for the long question, but I wanted to give out all the details. I don't think Visual Studio has anything to do with problems, but don't know for sure. I'm using VS Community Edition 2019, 16.1.3.

Update: Originally I had two problems. One getting the pointer updated and the other getting garbage data. I decided to split the two into two different questions.

Scheff

IMHO, the OP is not yet aware about scopes of variables:

void addElement(structure* userArray, const int tag)
{
  /* The global variable userArray is now invisible (eclipsed).
   * Instead, the local parameter userArray is used.
   * It has its own storage.
   */
}

Hence, whenever realloc() returns a different address then given it gets lost after leaving addElement().

realloc() may return

  1. the given address (of first argument)
  2. a new address
  3. a NULL pointer.

The heap managment which is used inside of realloc() might recognize that memory after block to grow is still free. Hence, the block can be grown in place. It might also be the case that the heap management provided earlier a larger block than actually requested. (This could be a strategy to prevent fragmentation of heap memory.) This is the reason why same address might be returned although more memory than before was requested.

If nothing of above was applicable a new block is allocated, old contents copied to new address, and old block is freed. (Otherwise, it would become a memory leak.)

If realloc() fails to do any of the above, it returns NULL.

Recalling the above, it's even worse: Whenever realloc() returns a different address then the memory at old address is freed. So, the global userArray (which is not updated) becomes dangling (pointing to freed memory). Accessing a dangling pointer is Undefined Behavior → good for any strange effects including a crash (Access Violation).

Concerning the third:

userArray = (structure*)realloc(userArray, userArrayAvailable * sizeof(structure));

might appear questionable.

(My personal thinking about this is: When memory is exceeded this means usually things have gone very wrong. The process has usually to be terminated as soon as possible. This will happen on most platforms when a NULL pointer is accessed ignoring the fact that the ugly system error message might scare the user and force her/him to make a support call. And, please, note my repeated usage of "usually"...)

The OP already observed the points 1. and 2. in diagnostic output.

There are various options to fix this issue:

  1. get rid of the global variable eclipsing:
void addElement(const int tag)
{
  /* unmodified code will now access the global userArray */
}
  1. use a pointer to pointer instead:
void addElement(structure **userArray, const int tag)
{
  /* all uses of userArray in code have to get an additional indirection operator
   * i.e. replace all occurrences of "userArray" by "(*userArray)"
   */
}
  1. return (potentially changed) userArray as result:
structure* addElement(structure *userArray, const int tag)
{
  /* unmodified code */
  return userArray;
}

has to be called now:

userArray = addElement(userArray, 13);

to reassign the (potentially changed) pointer to global variable.


I (personally) prefer design 3 in general. However, considering that addElement() accesses a variety of other global variables as well option 1 seems to me the most consistent fix.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

Getting garbage data doing realloc using a structure

From Dev

passing pointer to function and using realloc

From Dev

After using realloc the next pointer in array is lost

From Dev

SegFault while using Malloc/Realloc on an uninitialized pointer

From Dev

Updating a binary tree using a pointer

From Java

Problems with null pointer using mockito

From Dev

Using realloc by multiplying a pointer integer and sizeof(int) not working

From Dev

C - Crashing when using Realloc on a Pointer inside a Struct

From Dev

Confusion about using malloc/calloc pointer to hold the return value of realloc

From Dev

Necessity of double pointer when using realloc to manipulate array

From Dev

Problems with realloc in C

From Dev

realloc() problems with the old size

From Dev

Use realloc with pointer to pointer task

From Dev

Realloc setting pointer to empty

From Dev

Access to pointer passed to realloc

From Dev

Move pointer and realloc, C

From Dev

Negation of a void pointer Realloc

From Dev

Realloc char* inside structure

From Dev

Updating a nested data structure using lenses

From Dev

Problems updating

From Dev

Application Crash when printing structure using pointer

From Dev

accessing structure's member by using pointer

From Dev

Initialisation of pointer to structure using field elements

From Dev

Alternate way of "Accessing array of structure using pointer"

From Dev

How to access nested structure using pointer and array?

From Dev

Problems doing citations using RStudio with natbib with a bibliography style

From

Pointer problems

From Dev

Problems with realloc - "invalid next size"

From Dev

pointer being realloc'd was not allocated?

Related Related

HotTag

Archive