Dynamic allocation and pointers - c

int *ptr;
ptr=(int *)malloc(sizeof(int)*2);
ptr=100; /*What will happen if I put an asterisk(*) indicating *ptr=100? */
ptr++;
printf("ptr=%d",*ptr);
free(ptr);
So, I wanted the pointer to increment. I allocated a size of 4(2*2) for the pointer. But I couldn't understand how the pointer increments only by 2. And if I put an asterisk int the 3rd line,that is *ptr=100; It shows something else.

If you have int * ptr, then ptr++ increments the pointer by the size of a single int. If int is two bytes on your platform, that's why it increments by two.
*ptr = 100 would store the value 100 at the int pointed to by ptr, i.e. the first of the two ints that you allocated with your malloc() call.
ptr = 100 will attempt to assign the memory address 100 to ptr, which is almost certainly not what you want, as you would lose your reference to the memory you just malloc()ed, and what is at memory location 100 is probably not meaningful for you or accessible to you.
As it currently stands, if you were to do *ptr = 100 and then ptr++, your printf() call would result in undefined behavior since you'd have incremented the pointer to point to uninitialized memory (i.e. the second of the two ints you allocated with your malloc() call), whose contents you then attempt to output.
(*ptr)++ on the other hand would increment that 100 value to 101, leave the value of ptr unchanged, your printf() call would be fine, and output 101. The second of the two ints you allocate would still remain uninitialized, but that's no problem if you don't attempt to access it.
Also, don't cast the return from malloc(), ptr=(int *)malloc(sizeof(int)*2) should be ptr=malloc(sizeof(int)*2), or even better, ptr = malloc(sizeof(*ptr) * 2);

Try this:
int *ptr;
ptr = malloc(2 * sizeof *ptr);
printf("ptr = %p.\n", (void *) ptr); // Examine pointer before increment.
ptr++;
printf("ptr = %p.\n", (void *) ptr); // Examine pointer after increment.
You will see that the value of ptr is incremented by the number of bytes in an int. The C language automatically does pointer arithmetic in units of the pointed-to element. So a single increment of an int pointer in C becomes, at the machine level, an increment of the number of bytes of an int.
Notes
%p is the proper specifier to use when printing a pointer, not %d. Also, the pointer must be cast to void * or const void *.
ptr = malloc(2 * sizeof *ptr); is a cleaner way to allocate memory and assign a pointer than your original code, because:
Using sizeof *ptr causes the code to automatically adapt if you ever change the type of ptr. Instead of having to change the type in two places (where ptr is declared and where malloc is called), one change suffices. This reduces opportunities for errors.
malloc does not need to be cast to the destination type. It returns a void *, which C will automatically convert to the destination type of the assignment without complaint. (C++ is different.) It will still work if you cast it, but this can mask another problem: If you accidentally do not declare malloc (as by failing to include <stdlib.h>, and compile in an old version of C, malloc will be implicitly declared to return an int, and the cast will mask the error. Leaving the expression without a cast will cause a warning message to be produced when this happens.

This line changes value of address in pointer to some nonsense (100 will not be any valid address):
ptr=100;
Then you increment the pointer to 100 + sizeof(int) because the pointer has type of int* which automatically increments address by amount of bytes to get to the next integer that ptr points to.
At next line you dereference the invalid pointer so your code should crash, but the command is ok if your pointer had valid address:
printf("ptr=%d",*ptr);
To repair your code just don't change the pointer itself but change the data:
int *ptr;
ptr=(int *)malloc(sizeof(int)*2);
*ptr=123; /*What will happen if I put an asterisk(*) indicating *ptr=100? */
printf("ptr=%d",*ptr);
ptr++;
*ptr=234;
printf("ptr+1=%d",*ptr);
// you can set or get your data also this way:
ptr[0] = 333;
ptr[1] = 444;
printf("ptr[0]=%d",ptr[0]);
printf("ptr[1]=%d",ptr[1]);
free(ptr);

First thing you need to understand is a POINTER points to ADDRESS, when your assign 100 to ptr, it means your pointer ptr now points to memory location whose address is 100.
Secondly pointer arithmetic depends on type of pointer, in your case ptr is a pointer pointing to integer. SO when you increment ptr, it means it will jump to the memory location of next integer. So, ptr gets incremented by 2 (memory occupied by one int on your platform)

To be simple
ptr=100;
By this you are trying to store a int as an address to a pointer, which Is nonsense.
In other words you are trying to make the pointer ptr to point the address 100, which is not an address.
But by
*ptr=100;
You are trying to store value 100 to the address pointed by ptr, which is valid.
Also
ptr++;
Means that now ptr is pointing to ptr+4 or (ptr+2 for 16 bit compiler like tc) address.
Also for your particular code, you are just changing and incrementing the address pointed by ptr, but you are not storing any value at the address pointed by ptr.
So your code will print garbage value or it may also crash as 100 is not a valid address.
Also you should have done
ptr=(int*)100;
It would remove
warning: assignment makes pointer from integer without a cast [enabled by default]
But still it is undefined behaviour.

Related

Pointer layout in memory in C

I've recently been messing around with pointers and I would like to know a bit more about them, namely how they are organized in memory after using malloc for example.
So this is my understanding of it so far.
int **pointer = NULL;
Since we explicitly set the pointer to NULL it now points to the address 0x00.
Now let's say we do
pointer = malloc(4*sizeof(int*));
Now we have pointer pointing to an address in memory - let's say pointer points to the address 0x0010.
Let's say we then run a loop:
for (i = 0; i<4; i++) pointer[i] = malloc(3*sizeof(int));
Now, this is where it starts getting confusing to me. If we dereference pointer, by doing *pointer what do we get? Do we get pointer[0]? And if so, what is pointer[0]?
Continuing, now supposedly pointer[i] contains stored in it an address. And this is where it really starts confusing me and I will use images to better describe what I think is going on.
In the image you see, if it is correct, is pointer[0] referring to the box that has the address 0x0020 in it? What about pointer[1]?
If I were to print the contents of pointer would it show me 0x0010? What about pointer[0]? Would it show me 0x0020?
Thank you for taking the time to read my question and helping me understand the memory layout.
Pointer Refresher
A pointer is just a numeric value that holds the address of a value of type T. This means that T can also be a pointer type, thus creating pointers-to-pointers, pointers-to-pointers-to-pointers, and crazy things like char********** - which is simply a pointer (T*) where T is a pointer to something else (T = E*) where E is a pointer to something else (and so on...).
Something to remember here is that a pointer itself is a value and thus takes space. More specifically, it's (usually) the size of the addressable space the CPU supports.
So for example, the 6502 processor (commonly found in old gaming consoles like the NES and Atari, as well as the Apple II, etc.) could only address 16 bits of memory, and thus its "pointers" were 16-bits in size.
So regardless of the underlying type, a pointer will (usually) be as large as the addressable space.
Keep in mind that a pointer doesn't guarantee that it points to valid memory - it's simply a numeric value that happens to specify a location in memory.
Array Refresher
An array is simply a series of T elements in contiguously addressable memory. The fact it's a "double pointer" (or pointer-to-a-pointer) is innocuous - it is still a regular pointer.
For example, allocating an array of 3 T's will result in a memory block that is 3 * sizeof(T) bytes long.
When you malloc(...) that memory, the pointer returned simply points to the first element.
T *array = malloc(3 * sizeof(T));
printf("%d\n", (&array[0] == &(*array))); // 1 (true)
Keep in mind that the subscript operator (the [...]) is basically just syntactic sugar for:
(*(array + sizeof(*array) * n)) // array[n]
Arrays of Pointers
To sum all of this up, when you do
E **array = malloc(3 * sizeof(E*));
You're doing the same thing as
T *array = malloc(3 * sizeof(T));
where T is really E*.
Two things to remember about malloc(...):
It doesn't initialize the memory with any specific values (use calloc for that)
It's not guaranteed (nor really even common) for the memory to be contiguous or adjacent to the memory returned by a previous call to malloc
Therefore, when you fill the previously created array-of-pointers with subsequent calls to malloc(), they might be in arbitrarily random places in memory.
All you're doing with your first malloc() call is simply creating the block of memory required to store n pointers. That's it.
To answer your questions...
If we dereference pointer, by doing *pointer what do we get? Do we get pointer[0]?
Since pointer is just a int**, and remembering that malloc(...) returns the address of the first byte in the block of memory you allocated, *pointer will indeed evaluate to pointer[0].
And if so, what is pointer[0]?
Again, since pointer as the type int**, then pointer[0] will return a value type of int* with the numeric contents of the first sizeof(int*) bytes in the memory block pointed to by pointer.
If I were to print the contents of pointer would it show me 0x0010?
If by "printing the contents" you mean printf("%p\n", (void*) pointer), then no.
Since you malloc()'d the memory block that pointer points to, pointer itself is just a value with the size of sizeof(int**), and thus will hold the address (as a numeric value) where the block of memory you malloc()'d resides.
So the above printf() call will simply print that value out.
What about pointer[0]?
Again assuming you mean printf("%p\n", (void*) pointer[0]), then you'll get a slightly different output.
Since pointer[0] is the equivalent of *pointer, and thus causes pointer to be dereferenced, you'll get a value of int* and thus the pointer value that is stored in the first element.
You would need to further dereference that pointer to get the numeric value stored in the first integer that you allocated; for example:
printf("%d\n", **pointer);
// or
printf("%d\n", *pointer[0]);
// or even
printf("%d\n", pointer[0][0]); // though this isn't recommended
// for readability's sake since
// `pointer[0]` isn't an array but
// instead a pointer to a single `int`.
If I dereference pointer, by doing *pointer what do I get? pointer[0]?
Yes.
And if so, what is pointer[0]?
With your definitions: 0x0020.
In the image you see, if it is correct
It seems correct to me.
is pointer[0] referring to the box that has the address 0x0020 in it?
Still yes.
What about pointer[1]?
At this point, I think you can guess that it woud show: 0x002c.
To go further
If you want to check how memory is managed and what pointers look like you can use gdb. It allows running a program step by step and performing various operations such as showing the content of variables. Here is the main page for GNU gdb. A quick internet search should let you find numerous gdb tutorials.
You can also show the address of a pointer in c by using a printf line:
int *plop = NULL;
fprintf(stdout, "%p\n", (void *)pointer);
Note: don't forget to include <stdio.h>

In C, how does the specific type of pointer treat the memory space which point to?

Is a non-void pointer in C only cares about the memory space from its address to the address that the memory space is suitable for the type or ...?
Example:
typedef struct {...} A;
// the allocated memory space is much larger than sizeof(A)
A* temp = (A*) malloc(sizeof(A) + 256 * 256);
char* charPointer = (char*) temp;
charPointer += sizeof(A);
temp = (A*) charPointer;
In the last line, is temp still point to the new "A variable"? (seems an array of A allocated)
Update:
Does the cast in temp declaration & initialisation turns the memory space into an array of A, or memory space has no "type", the temp takes first (size: sizeof(A) ) memory space to store A variable, and the rest of memory space did nothing?
First of all a void* is implicitly convertible to any other pointer type (hint: the cast to value returned by malloc is superfluous).
Then memory means nothing, is how you interpret its contents that gives it a meaning.
So you are basically allocating sizeof(A) + SOME_LENGTH bytes of memory, then you tell the compiler that you want to treat a specific address starting from the allocated memory as a A*.
Nothing prevents you from doing it, and it will work as long as the memory reserved starting from the address is >= sizeof(A).
The only problem is how you release the memory. The derived address charPointer + sizeof(A) is not an address that is marked as something returned by malloc from the operating system. This means that the following code yields undefined behavior:
void* temp = malloc(sizeof(A) + sizeof(A));
A* ptr = temp + sizeof(A);
free(ptr);
Yes, it points to a "A struct". Allocated memory is only some of bytes, user can access that with any pointer type.
In these usages the user should be aware of dynamic memory allocation and pointers' concept in c, to avoid the segmentation fault problem.
In C, malloc returns the address of the first byte of a new memory allocation.
You have to cast it, (or at least put it in a pointer type).
Depending of your pointer type, if you increment this address, it will jump the correct amount of byte.
For exemple :
main.c
int* myPointer = NULL;
mypointer = (int*) malloc(sizeof(int) * 10);
//mypointer is the address of the first int
mypointer++;
//mypointer is now the address of the second int.
He knows how many byte he have to jump after the pointer incrementation, because he knows the type of your pointer (int*).
An int is 4Byte, so in the memory when you increment an int* it goes 4 address further.
So yes it point to the A struct, but if you cast the wrong type, you will have segmentation fault because it will not increment by 4 (in this exemple).
Hope it helped.

Assigning a Pointer the value of another pointer

I am trying to assign the value of fileOrDir to the value of copyFileOrDir. I want copyFileOrDir to be equal to the value of fileOrDir, not point to the same address. I thought it would be copyFileOrDir = *filrOrDir but I get errors. below is my code:
(fileOrDir gets its value from a command line argument)
char *fileOrDir = (char *)malloc(25*sizeof(char));
char *copyFileOrDir = (char *)malloc(25*sizeof(char));
copyFileOrDir = *fileOrDir;
Pointers point to a block of memory. If you set one pointer equal to another, you end up pointing to the same block of memory. If you actually assigned two different blocks, you should never want to then set one pointer to the other - you will be unable to free the memory.
Most likely you intend to do a memcpy which allows you to copy the contents of one memory block to another:
memcpy(void* destination, const void* source, size_t numberofbytes);
I am trying to assign the value of fileOrDir to the value of
copyFileOrDir.
You don't assign the value of a variable to the value of another variable. That's wrong to say. You assign a value to a variable. Think of a variable as a memory location. Also don't cast the result of malloc. That's not useful and can lead to bugs. Now let's come to your code snippet.
// don't cast the result of malloc
char *fileOrDir = malloc(25 * sizeof(char));
char *copyFileOrDir = malloc(25 * sizeof(char));
The following statement
copyFileOrDir = *fileOrDir;
tries to assign the object pointed to by fileOrDir, which is of type char, to copyFileOrDir, which is of type char * - a different type. This is an error. Also, by assigning copyFileOrDir, you lose the handle on the memory allocated by malloc causing memory leak. If you want to copy the buffer pointed to by fileOrDir to the buffer pointed to by copyFileOrDir, you should use memcpy.
memcpy(copyFileOrDir, fileOrDir, 25);
I think you're confused about pointers and values. You said you want the "value of copyFileOrDir to be equal to the value of fileOrDir." But the value of fileOrDir is just a pointer to a block of dynamically allocated memory that happens to be 25 bytes (assuming sizeof(char) is one byte) in size.
What you really want is for copyFileOrDir to point to a block of memory that is an exact copy of the memory pointed to by the value of fileOrDir. You can do this with memcpy.
char *copyFileOrDir = malloc(25*sizeof(char));
memcpy(copyFileOrDir, fileOrDir, 25*sizeof(char));
Also, I should point out that copyFileOrDir = *fileOrDir; makes no sense. In that case you are dereferencing fileOrDir (i.e. getting the value at the address pointed to by fileOrDir, which is a char) and assigning it to copyOfFileOrDir which is a char *. In other words, you are assigning a char to a char *.

Allocating a value to a pointer in c

I am trying to give a value to a pointer.
this code works fine
int i =5;
int *ptr ;
ptr = &i;
printf(" %d\n",*ptr);
but this code shows an error
int i =5;
int *ptr ;
*ptr = 5;
printf(" %d\n",*ptr);
can someone explain this to me?
int *ptr gets initialized to a random location, which possibly points to invalid memory, and you try to write 5 to that location.
When you declare int *ptr, you're creating a variable called ptr which can hold the address of an int. When you dereference it in *ptr = 5, you're saying "store 5 in the address that ptr points to" - but as ptr is uninitialised, where it points to is undefined. So you're invoking undefined behaviour.
An int * does not store an int, but just an address that points to one. There still has to be a real int at that address.
If you want to allocate an int that exists outside of the local scope, you can use malloc. A simple conversion of your example without error checking:
int *ptr = malloc(sizeof(int));
*ptr = 5;
printf(" %d\n",*ptr);
If you do use malloc, just remember to free the allocated memory when you're finished:
free(ptr);
The second version assigns 5 to the memory pointed to by ptr, but you haven't yet initialized ptr to point to a known location.
So it writes the value to the memory at whatever address happens to be in ptr, which is whatever was in memory where ptr was declared.
You can't deterrence a pointer that doesn't point to somewhere you own.
int* ptr;
That allocates space for the pointer, but it doesn't allocate space for the chunk the pointer points to.
Also, since it's not initialized, ptr has an indeterminate value. This means that not only does it likely point to something you don't own, it also would be rather difficult to check if it's a valid pointer. It's usually a good idea to initialize pointers to either NULL (or nullptr if available) or an actual location (like you did in the first example).

Need assistance in understanding this code using malloc and pointers

Here is a little snippet of code from Wikipedia's article on malloc():
int *ptr;
ptr = malloc(10 * sizeof (*ptr)); // Without a cast
ptr = (int*)malloc(10 * sizeof (int)); // With a cast
I was wondering if someone could help me understand what is going on here. So, from what I know, it seems like this is what's happening:
1) initialize an integer pointer that points to NULL. It is a pointer so its size is 4-bytes. Dereferencing this pointer will return the value NULL.
2) Since C allows for this type of automatic casting, it is safe not to include a cast-to-int-pointer. I am having trouble deciphering what exactly is being fed into the malloc function though (and why). It seems like we are getting the size of the dereferenced value of ptr. But isn't this NULL? So the size of NULL is 0, right? And why are we multiplying by 10??
3) The last line is just the same thing as above, except that a cast is explicitly declared. (cast from void pointer to int pointer).
I'm assuming we're talking about C here. The answer is different for C++.
1) is entirely off. ptr is a pointer to an int, that's all. It's uninitialized, so it has no deterministic value. Dereferencing it is undefined behaviour -- you will most certainly not get 0 out! The pointer also will most likely not point to 0. The size of ptr is sizeof(ptr), or sizeof(int*); nothing else. (At best you know that this is no larger than sizeof(void*).)
2/3) In C, never cast the result of malloc: int * p = malloc(sizeof(int) * 10);. The code allocates enough memory for 10 integers, i.e. 10 times the size of a single integer; the return value of the call is a pointer to that memory.
The first line declares a pointer to an integer, but doesn't initialize it -- so it points at some random piece of memory, probably invalid. The size of ptr is whatever size pointers to int are, likely either 4 or 8 bytes. The size of what it points at, which you'd get by dereferencing it when it points somewhere valid, is whatever size an int has.
The second line allocates enough memory for 10 ints from the heap, then assigns it to ptr. No cast is used, but the void * returned by malloc() is automatically converted to whatever type of pointer is needed when assigned. The sizeof (*ptr) gives the size of the dereferenced ptr, i.e. the size of what ptr points to (an int). For sizeof, it doesn't matter whether ptr actually points to a valid memory, just what the type would be.
The third line is just like the second, but with two changes: It explicitly casts the void * return from malloc() to an int *, to match the type of ptr; and it uses sizeof with the type name int rather than an expression of that type, like *ptr. The explicit cast is not necessary, and some people strongly oppose its use, but in the end it comes down to preference.
After either of the malloc()s ptr should point to a valid location on the heap and can be dereferenced safely, as long as malloc was successful.
For line 2 malloc() is allocating enough memory to hold 10 pointers.
malloc() is a general purpose function void so it must be cast to whatever type you actually want to use, in the above example pointer to int.

Resources