2

I want to create an integer pointer p, allocate memory for a 10-element array, and then fill each element with the value of 5. Here's my code:

//Allocate memory for a 10-element integer array.
int array[10];
int *p = (int *)malloc( sizeof(array) );

//Fill each element with the value of 5.
int i = 0;
printf("Size of array: %d\n", sizeof(array));
while (i < sizeof(array)){
    *p = 5;
             printf("Current value of array: %p\n", *p);
    *p += sizeof(int);
    i += sizeof(int);
}

I've added some print statements around this code, but I'm not sure if it's actually filling each element with the value of 5.

So, is my code working correctly? Thanks for your time.

Nathan Jones
  • 4,904
  • 9
  • 44
  • 70

7 Answers7

3

First:

*p += sizeof(int);

This takes the contents of what p points to and adds the size of an integer to it. That doesn't make much sense. What you probably want is just:

p++;

This makes p point to the next object.

But the problem is that p contains your only copy of the pointer to the first object. So if you change its value, you won't be able to access the memory anymore because you won't have a pointer to it. (So you should save a copy of the original value returned from malloc somewhere. If nothing else, you'll eventually need it to pass to free.)

while (i < sizeof(array)){

This doesn't make sense. You don't want to loop a number of times equal to the number of bytes the array occupies.

Lastly, you don't need the array for anything. Just remove it and use:

int *p = malloc(10 * sizeof(int));

For C, don't cast the return value of malloc. It's not needed and can mask other problems such as failing to include the correct headers. For the while loop, just keep track of the number of elements in a separate variable.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
  • 1
    IMHO a better reason not to cast is that, if the type of `p` changes, `p = malloc(10 * sizeof *p);` will work without alteration, while `p = (int *)malloc(10 * sizeof(int));` will require you to change the line. This is especially annoying if you use lots of `realloc`s. – Chris Lutz Oct 18 '11 at 21:49
2

sizeof of an array returns the number of bytes the array occupies, in bytes.

int *p = (int *)malloc( sizeof(array) );

If you call malloc, you must #include <stdlib.h>. Also, the cast is unnecessary and can introduce dangerous bugs, especially when paired with the missing malloc definition.


If you increment a pointer by one, you reach the next element of the pointer's type. Therefore, you should write the bottom part as:

for (int i = 0;i < sizeof(array) / sizeof(array[0]);i++){
    *p = 5;
    p++;
}
phihag
  • 278,196
  • 72
  • 453
  • 469
2

Here's a more idiomatic way of doing things:

/* Just allocate the array into your pointer */
int arraySize = 10;
int *p = malloc(sizeof(int) * arraySize);

printf("Size of array: %d\n", arraySize);

/* Use a for loop to iterate over the array */
int i;
for (i = 0; i < arraySize; ++i)
{
    p[i] = 5;
    printf("Value of index %d in the array: %d\n", i, p[i]);
}

Note that you need to keep track of your array size separately, either in a variable (as I have done) or a macro (#define statement) or just with the integer literal. Using the integer literal is error-prone, however, because if you need to change the array size later, you need to change more lines of code.

Platinum Azure
  • 45,269
  • 12
  • 110
  • 134
  • This is the solution I decided to implement for the assignment. Thanks so much for all of the great answers, everyone! – Nathan Jones Oct 18 '11 at 21:45
1
*p += sizeof(int);

should be

p += 1;

since the pointer is of type int *

also the array size should be calculated like this:

sizeof (array) / sizeof (array[0]);

and indeed, the array is not needed for your code.

fardjad
  • 20,031
  • 6
  • 53
  • 68
1
//allocate an array of 10 elements on the stack
int array[10];
//allocate an array of 10 elements on the heap.  p points at them
int *p = (int *)malloc( sizeof(array) );
// i equals 0
int i = 0;
//while i is less than 40 
while (i < sizeof(array)){
    //the first element of the dynamic array is five
    *p = 5;
    // the first element of the dynamic array is nine!
    *p += sizeof(int);
    // incrememnt i by 4
    i += sizeof(int);
}

This sets the first element of the array to nine, 10 times. It looks like you want something more like:

//when you get something from malloc, 
// make sure it's type is "____ * const" so 
// you don't accidentally lose it
int * const p = (int *)malloc( 10*sizeof(int) );
for (int i=0; i<10; ++i) 
    p[i] = 5;

A ___ * const prevents you from changing p, so that it will always point to the data that was allocated. This means free(p); will always work. If you change p, you can't release the memory, and you get a memory leak.

Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
1

Nope it isn't. The following code will however. You should read up on pointer arithmetic. p + 1 is the next integer (this is one of the reasons why pointers have types). Also remember if you change the value of p it will no longer point to the beginning of your memory.

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#define LEN 10

int main(void)
{
    /* Allocate memory for a 10-element integer array. */
    int array[LEN];
    int i;
    int *p;
    int *tmp;

    p = malloc(sizeof(array));
    assert(p != NULL);

    /* Fill each element with the value of 5. */
    printf("Size of array: %d bytes\n", (int)sizeof(array));

    for(i = 0, tmp = p; i < LEN; tmp++, i++) *tmp = 5;
    for(i = 0, tmp = p; i < LEN; i++) printf("%d\n", tmp[i]);

    free(p);

    return EXIT_SUCCESS;
}
megazord
  • 3,210
  • 3
  • 23
  • 31
1
//Allocate memory for a 10-element integer array.
int array[10];
int *p = (int *)malloc( sizeof(array) );

At this point you have allocated twice as much memory -- space for ten integers in the array allocated on the stack, and space for ten integers allocated on the heap. In a "real" program that needed to allocate space for ten integers and stack allocation wasn't the right thing to do, the allocation would be done like this:

int *p = malloc(10 * sizeof(int));

Note that there is no need to cast the return value from malloc(3). I expect you forgot to include the <stdlib> header, which would have properly prototyped the function, and given you the correct output. (Without the prototype in the header, the C compiler assumes the function would return an int, and the cast makes it treat it as a pointer instead. The cast hasn't been necessary for twenty years.)

Furthermore, be vary wary of learning the habit sizeof(array). This will work in code where the array is allocated in the same block as the sizeof() keyword, but it will fail when used like this:

int foo(char bar[]) {
    int length = sizeof(bar); /* BUG */
}

It'll look correct, but sizeof() will in fact see an char * instead of the full array. C's new Variable Length Array support is keen, but not to be mistaken with the arrays that know their size available in many other langauges.

//Fill each element with the value of 5.
int i = 0;
printf("Size of array: %d\n", sizeof(array));
while (i < sizeof(array)){
    *p = 5;
    *p += sizeof(int);

Aha! Someone else who has the same trouble with C pointers that I did! I presume you used to write mostly assembly code and had to increment your pointers yourself? :) The compiler knows the type of objects that p points to (int *p), so it'll properly move the pointer by the correct number of bytes if you just write p++. If you swap your code to using long or long long or float or double or long double or struct very_long_integers, the compiler will always do the right thing with p++.

    i += sizeof(int);
}

While that's not wrong, it would certainly be more idiomatic to re-write the last loop a little:

for (i=0; i<array_length; i++)
    p[i] = 5;

Of course, you'll have to store the array length into a variable or #define it, but it's easier to do this than rely on a sometimes-finicky calculation of the array length.

Update

After reading the other (excellent) answers, I realize I forgot to mention that since p is your only reference to the array, it'd be best to not update p without storing a copy of its value somewhere. My little 'idiomatic' rewrite side-steps the issue but doesn't point out why using subscription is more idiomatic than incrementing the pointer -- and this is one reason why the subscription is preferred. I also prefer the subscription because it is often far easier to reason about code where the base of an array doesn't change. (It Depends.)

sarnold
  • 102,305
  • 22
  • 181
  • 238