3

if we assign a pointer to another pointer, it's called "swap the pointers". For example,

float *temp, *ptr1, *ptr2;
temp = ptr1;
ptr1 = ptr2;
ptr2 = temp;

However, if we assign an array to a pointer, it's illegal because array is not really the pointer type. But look at the next 3 examples:

float arr[]={1.2, 1.9, 3.1};
float *ptr;
int i;
ptr = (float *)calloc(3,sizeof(float));
ptr = arr;
for (i=0;i<3;i++){
    printf("ptr[%d]=%f\n",i,ptr[i]);
}

This code snippet passed the compilation and ran correctly (illegal code gets the correct answer?):

ptr[0]=1.200000
ptr[1]=1.900000
ptr[2]=3.100000

If I add free(ptr) following the last line, i.e.

float arr[]={1.2, 1.9, 3.1};
float *ptr;
int i;
ptr = (float *)calloc(3,sizeof(float));
ptr = arr;
for (i=0;i<3;i++){
    printf("ptr[%d]=%f\n",i,ptr[i]);
}
free(ptr);  /*add free here*/

This time a warning came up:

warning: attempt to free a non-heap object ‘arr’ [-Wfree-nonheap-object]

int i;
int flag=0;
float arr1[3]={1.07,3.01,5.02};
float arr2[3]={2.07,6.01,9.02};
float arr3[3]={3.07,8.01,0.02};
float *ptr;
ptr = (float *)calloc(3,sizeof(float));
if(flag==0){
    ptr = arr1;
}
else if(flag==1){ 
    ptr = arr2;
}
else{ 
    ptr = arr3;
}
for (i=0;i<3;i++){
    printf("ptr[%d]=%f\n",i,ptr[i]);
}

It can run correctly with different flag, but if I add free(ptr) at last line, it still has warning like the previous.

Does anybody help analyze why?

4
  • 1
    On one line you allocate enough bytes to hold three floats, and set the value of ptr to hold that memory location. On the next line change the value of ptr to hold the address of the arr array, orphaning the memory you previously allocated. Since the memory ptr points to is actually a literal array of three floats you cannot free it. The memory you should be freeing has been leaked. Commented Jul 12, 2018 at 1:38
  • 1
    OT: when calling any of the heap allocation functions: malloc calloc realloc 1) the returned type is void* which can be assigned to any pointer. Casting just clutters the code, making it more difficult to understand, debug, etc. 2) always check (!=NULL) the returned value to assure the operation was successful Commented Jul 12, 2018 at 1:56
  • 2
    regarding: ptr = arr1; and similar statements. This overlays the value set in the pointer via the call to calloc(), resulting in a memory leak. Perhaps you meant: memcpy( ptr, arr1, sizeof( arr1) ); Note: in C, referencing the name of an array degrades to the address of the first byte of the array. Commented Jul 12, 2018 at 2:00
  • @user3629249 - I know what you mean, but technically an array is "converted to an expression with type ''pointer to type'' that points to the initial element of the array object" (degrades is a bit odd, but you will see decays -- which itself isn't in the standard, but it is commonly understood) See: C11 Standard - 6.3.2.1 Lvalues, arrays, and function designators (p3). Commented Jul 12, 2018 at 6:41

4 Answers 4

3
ptr = (float *)calloc(3,sizeof(float));

Here, you set ptr to a block of malloc'ed memory big enough for 3 floats. Then on the next line:

ptr = arr;

You overwrite the value of ptr, causing a memory leak, with arr. This is legal because in an assignment like this an array decays into a pointer to its first element.

When you then print the values that ptr point to, you get the values in arr because that's where ptr points.

This is also why calling free on ptr is invalid since it no longer points to allocated memory.

As for the last bit of code, this is an invalid initializer:

float arr1[3]={{1.07,3.01,5.02}};

When I ran this code, flag=0 showed 0 for the second and third values, while flag=1 and flag=2 showed all the expected values.

You only need one set of braces:

float arr1[3]={1.07,3.01,5.02};
Sign up to request clarification or add additional context in comments.

4 Comments

For the last code, if I add free(ptr); at last line, it still has warning like the previous.
@coco Yes, for the same reason: you overwrote the malloc'ed memory with the address of a local array.
So this code snippet is still useless because we have to de-allocate the memory after using them. Does that mean I have to find another way to assign the array to the pointer, like "for" loop?
@coco You either have to copy the local array to the allocated memory (either with memcpy or a loop), or get rid of the allocation completely.
2

Solution without error

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

int main()
{
    float arr[]={1.2, 1.9, 3.1};
    float *ptr;
    int i;
    ptr = (float *)calloc(3,sizeof(float*));

    if(ptr == NULL){
     perror("calloc");
     return -ENOMEM;
    }
    //ptr = arr;

    // here you need to do something like this
    ptr[0] = arr[0];
    ptr[1] = arr[1];
    ptr[2] = arr[2];

    for (i=0;i<3;i++){
       printf("ptr[%d]=%f\n",i,ptr[i]);

           }
        free(ptr);
}

4 Comments

Not an error, but there is no need to cast the return of malloc (or calloc or realloc), it is unnecessary. See: Do I cast the result of malloc? -- and you sure have a funny way of formatting braces...
yes, you're right but for portability between other languages like c++, I like to do so.
Well, that's why there is something called the C-Standard and a separate document called the C++-Standard. Also, you should validate the return of calloc, e.g. (if (ptr != NULL)) before making use of the memory. The allocation functions return NULL on failure (and they do fail). Recall, when answering questions, you step into the roll of teacher. You are helping a new student learn to program. Make sure he remembers you as one of the good teachers :)
done!! thanks, from the next time i make sure everything should be clear .. :)
1

There's absolutely nothing illegal at all in your code when you point a pointer to an array. It will not even give you a warning.

A pointer is a pointer and it can point at anything. Sometimes you may need to cast it, but pointing at an array of the same base type is not only completely valid, it's even common.

However, you can only use free on memory that's allocated on the heap (malloc, calloc, etc). An array is allocated on the stack and does not need to be freed, and as you have already seen, you will get a runtime error if you do.

2 Comments

But for "swap the pointer" (like the very first example), we can "free" the pointers. Is it because the dynamically allocated memory still exits, while an array can overwrite it with constant pointer making the pointer no longer dynamically allocated?
@coco In the very first example you have not allocated any memory at all, so no, you cannot free them.
1

Assign an array

In C arrays may not be assigned.

You need to assign element by element.

What happens here

float arr[]={1.2, 1.9, 3.1};
float *ptr;

ptr = arr;

is that you assign to ptr the address of arr[0]. This is called "The array is decayed to a pointer (the address of) it's first element"

No array elements get copied!

To prove this just do

arr[0] = 42.;

next and then run the print-loop

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

you will get (something like):

ptr[0] = 42.000
ptr[1] = 1.9000
...

2 Comments

Actually it can get copied. See the second code snippet, it can return the correct values.
@coco: Did you read and try my proposal to prove that no elements are "copied", in none of the three cases you show?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.