0

Is there a way to have a pointer in C that points to an array be reassigned so that it points to an array of a smaller size? For example, if I have a pointer ptr that originally points to an array s of size 3, and there also exists an array s1 of size 2, could I reassign ptr so that it points to s and thus points to a smaller array?

I tried the following code:

void changePtr(double* ptr);

int main()
{
    double *ptr;
    ptr = (double*)malloc(sizeof(double)*3);
    double s[3]={1,2,3};
    ptr=s;
    changePtr(ptr);

    return 0;
}

void changePtr(double* ptr) {

    double s1[2]={4,5};
    free(ptr);
    ptr = (double*)malloc(sizeof(double)*2);
    ptr=s1;
}

But when I run this in VIsual Studio, I get an error at free(ptr) which says Debug Assertion failed! Expression: _CrtIsValidHeapPointer(block)

Why is this?

EDIT

New code is:

void changePtr(double* ptr);

int main()
{
    double *ptr;
    ptr = (double*)malloc(sizeof(double)*3);
    double *s;
    s = (double*)malloc(sizeof(double)*3);
    s[0]=1; s[1]=2; s[0]=3; 
    for (int i=0; i<3; i++){
        ptr[i]=s[i];
    }

    changePtr(ptr);

    for (int i=0; i<2; i++){
        printf("%f\t", ptr[i]);
    }


    free(ptr);
    free(s);

    return 0;
}

void changePtr(double* ptr) {
    free(ptr);
    double *s1;
    s1 = (double*)malloc(sizeof(double)*2);
    s1[0]=11; s1[1]=12;

    ptr = (double*)malloc(sizeof(double)*2);

    for (int i=0; i<2; i++){
        ptr[i]=s1[i];
    }
}

But I get garbage values like -1456815990147....1 when I print out the values of ptr after calling changePtr. Why is this?

user5739619
  • 1,748
  • 5
  • 26
  • 40
  • The last line in changePtr() looks fishy. You are assigning a pointer to an array that was created locally. When the function returns, the array will go out of scope, thus you are pointing at a memory location that does not belong to your program. Best thing to do is to attach a debugger and run the program step by step. – John M. May 21 '19 at 23:56
  • I pasted new code into the OP. I am getting garbage values now in `ptr`. Why is this? – user5739619 May 22 '19 at 00:22
  • In your printf you use the %f modifier, try using the %lf modifier and check the results again (%f is for floats, doubles need %lf). – John M. May 22 '19 at 00:32
  • I still get the garbage values with `%lf` – user5739619 May 22 '19 at 00:34
  • 1
    Have you tried using printf inside the function right before it returns? Do you still get garbage values? – John M. May 22 '19 at 00:39
  • Yes, inside the `changePtr`, it correctly outputs 11 and 12 – user5739619 May 22 '19 at 00:43
  • Just in case, check the address of ptr before, during and after the function, you might get a dangling pointer after the function returns. Also you have a memory leak in changePtr. You never free the s1 pointer. – John M. May 22 '19 at 00:47
  • the address of the pointer changes from before and during the function, but then its address after the function is the same as it was before the function – user5739619 May 22 '19 at 00:54
  • That means the previous values were overwritten with garbage values after you called free. When a memory location is freed, it doesn't belong to your program anymore and can be overwritten by another application that has claimed that memory location. When the function returns, the pointer that you previously freed returns back to that location and now points at a memory section that does not belong to your program and contains garbage... – John M. May 22 '19 at 01:10
  • ... In c/c++ the moment you free/delete a memory location the data it contains can be changed anytime without the ability of recovering it back. If you move the contents of the function in main(), most likely you won't run in to that problem, it's just the function that returns the pointer to the old invalid location. BTW if you are using C99 (I think it also applies to C89) you don't need to cast the result of malloc(). For more details see https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc – John M. May 22 '19 at 01:11
  • how could I change the code so that when the function returns, the pointer doesn't return to that location I had freed and instead points to the new location? – user5739619 May 22 '19 at 01:13
  • You could probably try to save the address of the new location in the function and return it either by value or by using a parameter. Not sure if it will work though. Something like returnAddress = &ptr; return returnAddress; Obviously you need to change the return type to int from void. – John M. May 22 '19 at 01:15
  • Sorry I meant int * not int. – John M. May 22 '19 at 01:24
  • C uses pass by value , you are passing `ptr` by value to the function which means the function receives a copy of `ptr`. You seem to expect that `ptr = bla;` in the function will have some effect on `main`, this is not true – M.M May 22 '19 at 02:26
  • so then how do I pass the pointer by reference in C? – user5739619 May 22 '19 at 05:01

2 Answers2

1

Edit 1

To your original question:

Short answer: Yes, you can reassign a pointer to a smaller array in C.

Long answer: The short answer is misleading. Arrays are also simply pointers in C. And for a better understanding of this concept, you might want to read this thread, especially take a look at this answer.


The problem is that you try to de-allocate the memory on stack.

Whenever you create a local variable, à la int a = 5, it's pushed on the stack, that is this variable gets memory allocated on stack and after the function call (main()) is over the memory is de-allocated - all this happens automatically!

In your case, here is what happens:

// memory is allocated automatically on stack for the local variable "s"
double s[3]={1,2,3};

// assign the stack address of "s" to "ptr"
ptr = s;

// de-allocate the managed stack address of "s", which is NOT allowed!
free(ptr);

Creating dynamic memory, e.g. via malloc, on the other hand happens in the heap memory, which needs to be managed by the programmer, that is allocating (malloc()) and de-allocating (free()) memory is allowed and must be done with great care.

So, in your programm when it hits this line free(ptr);, the assertion fails, because the target memory address doesn't meet the requirement -> IsValidHeapPointer: No ptr is not a valid heap pointer, because it holds the stack address of the s variable at that point. :)


Edit 2

I get garbage values like -1456815990147....1 when I print out the values of ptr after calling changePtr. Why is this?

It's because, you free the memory of ptr in changePtr(ptr) first, that is the content of ptr is written with some "garbage" value.

And then here you allocate new memory and assign it to ptr:

ptr = (double *) malloc(sizeof(double) * 2); 

After this point, the changes you make via ptr (i.e. ptr[i] = 12) has no influence on the previous address which ptr held. So, simply remove the free(ptr) and the above line, you don't need them.


Edit 3

So does ptr now only contain 2 values, right? After I delete that line you mentioned, and then printed out the values in ptr, it shows the correct values for ptr[0] and ptr[1] and then a garbage value for ptr[2].

Correct. ptr[2] is freed before, so unless you assign a new value to that address, it will remain a garbage. Also be careful after you have freed heap memory. You should not use the pointer to access memory or assign a new value to it. Consider your pointer "void" after you call free on it.

When I tried to print the size of it with printf("%d", sizeof(ptr)), it shows 8 and printf("%d", sizeof(ptr)/sizeof(ptr[0]) shows 1.

ptr is a pointer. sizeof(ptr) returns 8 bytes, that's the size of address that a pointer in your system holds. So, it is not the size of array... Further, determining the size of a pointer (which points to an array and passed to a function as reference - like you did changePtr(ptr)) during the runtime is programmatically not possible, you have to explicitly pass the array size to a function, if you want to do some loop operations.

  • I pasted new code into the OP. I am getting garbage values now in `ptr`. Why is this? – user5739619 May 22 '19 at 00:22
  • @user5739619 updated my answer. Please visit the link I provided in Edit 1. Also, here you can find a nice read about `pointers` in C: https://beginnersbook.com/2014/01/c-pointers/ –  May 22 '19 at 00:57
  • Thanks for the links. So does `ptr` now only contain 2 values, right? After I delete that line you mentioned, and then printed out the values in `ptr`, it shows the correct values for `ptr[0]` and `ptr[1]` and then a garbage value for `ptr[2]`. When I tried to print the size of it with `printf("%d", sizeof(ptr))`, it shows 8 and `printf("%d", sizeof(ptr)/sizeof(ptr[0])` shows 1. – user5739619 May 22 '19 at 01:02
  • 1
    So if I do `free(ptr)` and then `ptr[i]=s1[i]`, that reassigns the address that `ptr` points to, right? If so, why would doing that without removing `ptr = (double *) malloc(sizeof(double) * 2)` "have no influence on the previous address which ptr held"? – user5739619 May 22 '19 at 01:31
  • @user5739619 updated my answer. You should re-read my **Edit 2** and **Edit 3**. I would highly recommend you to read about pointers thoroughly. You will then be able to answer all your questions yourself, trust me. :) –  May 22 '19 at 01:33
1

Well, when you do

double s[3]={1,2,3};

That memory is not managed by you, so you can not free it. You can only use free when you allocate memory using malloc or calloc (i.e. dynamically allocated memory). Additionally, you have a memory leak there because

ptr=(double*)malloc(sizeof(double)*3); // here you allocate memory 
...
ptr = s; // here you change the pointer address but allocated memory is never freed

a solution would be to use a for loop to copy the values from s to ptr, and do the same in changePtr to copy values from s1 to ptr.

  • I pasted new code into the OP. I am getting garbage values now in `ptr`. Why is this? – user5739619 May 22 '19 at 00:22
  • Well in the function changePtr(double* ptr) you free memory, and then allocate memory in a different location. However, in main function ptr stills points to the old address. I think a solution is use & operator in changePtr(double &ptr). Thus ptr is a reference to ptr in main and by changing it in Changeptr function will also modify it in main function – Jonathan Arley Monsalve Salaza May 22 '19 at 20:15