17

I have some confusions/problems about the usage of pointers in C. I've put the example code below to understand it easily. Please notice differences of these codes. If you have some problem understanding it, please have a feedback.

This doesn't work.

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

void process() {
    int *arr;
    arr=(int*)malloc(5*sizeof(int));
    arr=(int*){3,1,4,5,2};
    for(int z=0;z<5;z++) {
        printf("%d ",arr[z]);
    }
    printf("\n");
}

int main() {
    process();
    return 0;
}

But this works.

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

void process() {
    int *arr;
    arr=(int*)malloc(5*sizeof(int));
    arr=(int[]){3,1,4,5,2};
    for(int z=0;z<5;z++) {
        printf("%d ",arr[z]);
    }
    printf("\n");
}

int main() {
    process();
    return 0;
}

This also works too. Why? I didn't allocate memory here.

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

void process() {
    int *arr;
    arr=(int[]){3,1,4,5,2};
    for(int z=0;z<5;z++) {
        printf("%d ",arr[z]);
    }
    printf("\n");
}

int main() {
    process();
    return 0;
}

Why aren't they same?

    arr=(int*){3,1,4,5,2};
    arr=(int[]){3,1,4,5,2};

Is there any other way to initializing array of integer pointer, not using in this individual assigning way?

arr[0]=3;
arr[1]=1;
arr[2]=4;
arr[3]=5;
arr[4]=2;

How can i get the size/number of allocation in memory of pointer so that i can use something like for(int z=0;z<NUM;z++) { instead of for(int z=0;z<5;z++) { statically?

Any answer is highly appreciated.

Thanks in advance.

cola
  • 12,198
  • 36
  • 105
  • 165
  • Are you using gcc? `arr=(int[]){3,1,4,5,2};` I think isn't valid C++. – Jesse Good May 16 '12 at 23:59
  • Yes, i'm using gcc compiler. Is it not valid C++? `arr=(int[]){3,1,4,5,2};` – cola May 17 '12 at 00:02
  • Yes, they are called [compound literals](http://gcc.gnu.org/onlinedocs/gcc/Compound-Literals.html) and gcc accepts them in C++ as an extension (try compiling with `-pedantic` and you should get a warning). – Jesse Good May 17 '12 at 00:09
  • 3
    You have stdlib.h there AND iostream. Also namespace AND malloc. What language is that ? C+ ? – ScarletAmaranth May 17 '12 at 00:11
  • @ScarletAmaranth, I removed iostream and namespace. It's C. Thanks. – cola May 17 '12 at 00:16
  • We know following two declaration are not allowed: int *ptrInt = {23,44,65,555}; char *ptrChar = {'2','3'}; But how come char *str2 = "Hello"; is allowed? – Mahesha Padyana Jul 27 '15 at 10:24

4 Answers4

19

The malloc calls in the first few examples allocate a block of memory and assign a pointer to that memory to arr. As soon as you assign to arr again, the pointer value is overwritten, and you've lost track of that allocated memory -- i.e., you've leaked it. That's a bug right there.

In other words, if you allocate a block of memory using using malloc(), then you can write data into it using array syntax (for example):

int* arr = (int *) malloc(sizeof(int) * 5);
for (int i=0; i<5; ++i)
    arr[i] = i;

But you can't assign anything else directly to arr, or you lose the pointer to that block of memory. And when you allocate a block using malloc(), don't forget to delete it using free() when you don't need it anymore.

An array is not a pointer-to-integer; it's an array. An array name is said to "decay to a pointer" when you pass it as an argument to a function accepting a pointer as an argument, but they're not the same thing.

Regarding your last question: that's actually the difference between an array and a pointer-to-type: the compiler knows the size of an array, but it does not know the size of a block pointed to by an arbitrary pointer-to-type. The answer, unfortunately, is no.

But since you're writing C++, not C, you shouldn't use arrays anyway: use `std::vector'! They know their own length, plus they're expandable.

Ernest Friedman-Hill
  • 80,601
  • 10
  • 150
  • 186
  • Understanding STL's vector is too hard for the beginner. – Stepan Yakovenko May 17 '12 at 00:24
  • @Ernest Friedman-Hill, I didn't understand, does the code have a bug i have posted? Which one has the bug? – cola May 17 '12 at 00:41
  • @user643540 -- I hope you're joking. It's easier than falling off a log. – Ernest Friedman-Hill May 17 '12 at 00:59
  • @prime -- The two which include `malloc` use it incorrectly, and so you leak memory as a result, which is a bug. – Ernest Friedman-Hill May 17 '12 at 01:00
  • @ErnestFriedman-Hill, Are you telling me not to use malloc? Or how should i use malloc, then assign values? – cola May 17 '12 at 01:03
  • @prime -- you can definitely use `malloc`, you just have to use it correctly; see my edit. – Ernest Friedman-Hill May 17 '12 at 01:06
  • @ErnestFriedman-Hill, If i don't assign values using a for loop, what is the other way? Is it the `memcpy` the only option to assign values after using `malloc`? What will happen if i don't do `free` at last? – cola May 17 '12 at 01:32
  • @prime :if you dont free the arr then when function gets executed it goes out of stack and the arr still resides in the memory but cant be referenced and will be dangling .this allocated space cant be re-utilised – Imposter May 17 '12 at 06:10
7

When you say: ptr = {1,2,3,4,5}, you make ptr point to a memory in the data segment, where constant array {1,2,3,4,5} resides and thus you are leaking memory. If you want to initialize your memory, just after allocation, write: ptr[0]=1; ptr[1]=2; and so on. If you want to copy data, use memcpy.

Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132
Stepan Yakovenko
  • 8,670
  • 28
  • 113
  • 206
  • I don't want to assign value individually like i said there. – cola May 17 '12 at 00:04
  • How do you want to fill allocated memory? May be you just want to read data from your constant array? Then just say: ptr = {1,2,3,4,5} without alloc() or new[]. But you wouldn't get a chance to modify this array. – Stepan Yakovenko May 17 '12 at 00:18
  • Your answer is bit confusing. What is ptr here array or pointer? Can you please post complete C code with ptr? – cola May 17 '12 at 00:20
  • 1
    Pointer and array is the same in C. If you want, please skype me (stiv.yakovenko), I'll try to explain it using diagram in mspaint. – Stepan Yakovenko May 17 '12 at 00:22
  • Or you may ask here. But drawing is essential. – Stepan Yakovenko May 17 '12 at 00:24
  • If you use array like `int a[]={1,2,3,4,5};` then you can change the value of array like `a[4]=10;` – cola May 17 '12 at 00:32
  • 4
    @stiv Sorry to contradict you, but arrays and pointers are two very different things in C. Just try this if you don't believe me: `int a[3]; printf("sizeof(a) = %d\n", (int)sizeof(a)); printf("sizeof(a + 0) = %d\n", (int)sizeof(a + 0));` The first `printf()` prints 12, the second 8. Why? Because in `a + 0` the array identifier decayed into a pointer, and that is something very different than an array. – cmaster - reinstate monica Jan 06 '14 at 13:03
2

The comma-separated list of values is a construct for initializing arrays. It's not suitable for initializing pointers to arrays. That's why you need that (int[]) - it tells gcc to create an unnamed array of integers that is initialized with the provided values.

gcc won't let you losing the information that arr is an array unless you really want to. That's why you need a cast. It's better that you declare arr as an array, not as a pointer. You can still pass it to the functions that accept a pointer. Yet gcc would not let you leak memory with malloc:

error: incompatible types when assigning to type ‘int[5]’ from type ‘void *’

If you want a variable that can be either an array or an pointer to allocated memory, create another variable for that. Better yet, create a function that accepts a pointer and pass it either an array or a pointer.

proski
  • 3,603
  • 27
  • 27
0

I feel like I can clarify the accepted answer further.

When you initialize an array with e.g.

int arr1[]={1,2,3,4,5};

This reserves memory on the stack, populates it with the values {1,2,3,4,5}, and sets arr to a pointer to this block of memory.

When you initialize an array with new:

arr2 = new float[5];

This reserves memory on the heap and returns a pointer to this block of memory. If you then called:

arr2 = arr1;

You would lose the address of the heap memory you set aside for arr2. This is memory leakage.

The correct way to do this would be to copy the arr1 values from the stack to the heap using memcpy:

memcpy(arr2, arr1, sizeof(arr1)); // src, dest, #bytes