initiations pointer to arrays - c

//1
char** p;
p[0]="Test";
//2
char** array;
array = realloc(array, sizeof(char*)*((*size)+1));
array[*size] = (char*)malloc(sizeof(char)*(strlen(input)+1));
Why does the first code fails in the second line, while the the second code works fine, doesn't array[*size] is just like p[0]?

Examining the code:
char **p; // Declared, but uninitialized
p[0] = "test"; // Setting value to it?
p is uninitialized, and as such, trying to access and set memory with it is UB, or undefined behavior. Failing is much better than potential alternatives.
For the second piece of code, assuming size is some pointer not included in the snippet.
char** array
array = realloc(array, sizeof(char*)*((*size)+1)); // Allocating.
array[*size] = (char*)malloc(sizeof(char)*(strlen(input)+1));
So, strictly speaking, calling realloc with an uninitialized pointer is UB, by chance array is equal to Null.
Note that:
If ptr is NULL, the behavior is the same as calling malloc(new_size).
As such, realloc will allocate a chunk of memory and pass it to array.
You then dereference the pointer (which is no longer pointing to Null but a valid spot in memory), and malloc it, which does not crash.
From the best guess, while this is undefined behavior, p is possibly Null in both cases, and the first one crashes when trying to dereference it, and the second one successfully gets malloced.

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>

Need help in understanding malloc(0) for my example [duplicate]

This question already has answers here:
Undefined, unspecified and implementation-defined behavior
(9 answers)
What does malloc(0) return? [duplicate]
(9 answers)
Closed 6 years ago.
I am trying to understand inners of double pointer (which is pointer holding another pointer) to form an array of pointers. So, I am trying to run the following code by experimenting on malloc to debugging and see how it works. I am unable to understand what malloc(0) does in my case, but my code works by outputting "Hello World".
What is the diff between
pToCharsPointers = (char**) malloc(0);
and
pToCharsPointers = (char**) malloc(2 * sizeof(char*));
Please someone clarify what it is doing in my case.
#include <stdio.h>
char **pToCharsPointers;
int main(void)
{
pToCharsPointers = (char**) malloc(0);
char* pToChars = "Hello";
*pToCharsPointers = pToChars;
*(pToCharsPointers + 1)= "World";
printf("%s %s\n", *(pToCharsPointers + 0), *(pToCharsPointers + 1));
return 0;
}
Also, I would really appreciate if you anyone could explain how double pointers works with an example in memory for visualizing as I fail to see myself even though I tried to read about this in many places.
EDIT: Thanks everyone for sharing your answers, and it really helped to understand. I got a valid pointer with malloc(0) when I printed it, and can dereference it also without issues during multiple tries. Wanted to understand why its working. Seems like in my case undefined behavior was actually a expected one.
In your code
(char**) malloc(0);
is wrong for two reasons, like
Passing size as 0 is implementation defined behaviour and the returned pointer cannot be dereferenced. Quoting the manual page,
If size is 0, then malloc() returns either NULL, or a unique pointer value that can later be successfully passed to free().
Please see this discussion on why not to cast the return value of malloc() and family in C..
Any code, attempting to use the returned pointer for a code like yours, will be essentially dereferencing invalid memory which invokes undefined behavior. So, the output/behaviour of your program can neither be predicted nor reasonified.
OTOH, a statement like
pToCharsPointers = malloc(2 * sizeof(char*));
is valid but you ought to check the validity of the returned pointer to ensure malloc() is success.
I will try to explain:
pToCharsPointers = (char**) malloc(0);
this line will bring to pToCharPointers a pointer that you can't use
but you can't know if an error will come. don't do that!
char* pToChars = "Hello";
*pToCharsPointers = pToChars;
this line will bring *pToCharsPointers to pToChar that pointing to the "Hello".
*(pToCharsPointers + 1)= "World";
this line will write in *(pToCharsPointers + 1), that you can't know to where it is pointing, "World". also, an option to an error but not for sure.
printf("%s %s\n", *(pToCharsPointers + 0), *(pToCharsPointers + 1));
this line will print "Hello Wolrd" if you didn't get any errors yet.
It simply asks to allocate zero bytes. It is up to the implementation of malloc if it should return a null pointer or not.
Even if it returns a non-null pointer, you can't dereference it since it will automatically be out of bounds. Dereferencing the returned pointer will lead to undefined behavior in both cases.
When you do malloc(2 * sizeof(char*)) you allocate enough space for two pointers to char.
You forgot to include <stdlib.h>. Calling malloc() without a proper definition has undefined behavior. Explicitly casting its return value hides the fact that the compiler may assume it returns an int value. This cast is necessary in C++, where calling a function without a prior definition is invalid, but it is counter-productive in C.
Regarding your question: allocating a block of size zero can have two possible outcomes, depending on the implementation of your C library:
malloc(0) can return NULL, and attempting to store values at this address has undefined behavior.
malloc(0) can return a valid non-null pointer, but this pointer cannot be dereferenced, nor used to store anything as the size of the object it points to is 0.
In both cases, your code has undefined behavior, which may or may not be a crash.

Linked Lists in C, last node point to NULL?

In C, must I always initialize my last node pointing to NULL? I generally see this happening in tutorials and in books. But to my understanding, an unitialized pointer holds the same address as a NULL pointer. So why initialize?
But to my understanding, an uninitialized pointer holds the same address as a NULL pointer
It might, by (bad) luck.
In any case reading out an uninitialised pointer invokes undefined behaviour. Whether this would lead to a crash (or any other "strange" behaviour) sooner or later is unknown, as by the nature of undefined behaviour.
However depending on how the memory the pointer variable "lives" in is allocated, the memory might come as "already" initialised, if allocating
it statically or
via calling calloc()
Both methods allocate memory and 0 it out in advance. Which, for most recent systems, is sufficient to have a pointer variable (living inside this memory) carrying the value of NULL.
But please note that there still might be implementations around that use a different bit pattern for NULL than just 0-bits. So to stay 100% portable it is good advice to always initialise with NULL explicitly and not rely on implicitly cleared out memory. And btw, this also helps the potential reader of your sources.
When you create a pointer without initializing it, let's say
char *ptr;
The memory points to some bytes (depending on your pointer type).
Those bytes, may be anything. Like some previous initialized unfreed pointer, or, to some garbage.
Which is not the same as a NULL pointer.
To avoid that, you should take the habit of initializing every of your pointers (except for globals and statics which are initialized to 0) and, add a NULL every-time you work with arrays or anything containing multi-elements.
Let's say that in this case, NULL is the '\0' of the array/list.
For example, if you want to create an array containing a few char *, do it this way :
void function()
{
char *array[4];
array[0] = strdup("Jason");
array[1] = strdup("Mike");
array[2] = strdup("Nicole");
array[3] = NULL;
}
It helps you not to go further than the memory you previously allocated for this pointer, avoiding memory fails, and segmentation faults. In case you're using a counter to get through every case of this array.
Otherwise, don't use NULL everywhere, if you allocated a string, don't fill it with NULL after on.
int main()
{
char *ptr;
if ((ptr = malloc(sizeof(char) * 42)) == NULL)
return (-1);
ptr = NULL;
return (0);
}
This won't work because you're sending NULL into the bytes you cleaned straight before.
If you want to properly use a pointer and clean it before using it, you can use memset. Which will send a x amount of the same byte into the pointer, cleaning the garbage that might be in it by the bytes you passed into memset parameters.
You might think that null pointer is the pointer that is uninitialized, but it's wrong. Null pointer is a special pointer which doesn't points to anywhere.
// To declare a null pointer.
int *ptr=NULL;
if(ptr==NULL) //..do something..
Functions like malloc() and getchar() returns null pointer in case they are unable to perforn their task or complete the task.
An uninitialized pointer can hold any garbage value.
an uninitialized local variable's value is undefined. while the static or global will grantee to be 0.
it is a good practice to initialize all variable you defined, otherwise, it may result very very trick bug.
Contrary to your understanding, the content of an uninitialized pointer is undefined. Only if the object is statically allocated is it guaranteed to be zero initialised.

Difference between initializing a string with (char *)malloc(0) and NULL

Why allocating a 0 size char block works in this case? But if I write char *string = NULL; it won't work.
I'm using Visual Studio.
int main()
{
char *string = (char *)malloc(0);
string[0] = 'a';
string[1] = 'b';
string[2] = 'c';
string[3] = 'd';
string[4] = '\0';
printf("%s\n",string);
return 0;
}
First let me state, as per the man page of malloc()
The malloc() function allocates size bytes and returns a pointer to the allocated memory. The memory is not initialized. If size is 0, then malloc() returns either NULL, or a unique pointer value that can later be successfully passed to free().
a call like malloc(0) is valid itself, but then, we need to check the validity of the returned pointer. It can either
Return NULL
Return a pointer which can be passed to free().
but anyways, dereferencing that pointer is not allowed. It will cause out-of-bound memory access and cause undefined behaviour.
That said, two important things to mention,
Please see why not to cast the return value of malloc() and family in C.
Please check the return value of malloc() before using the returned pointer.
So, to answer your question,
Difference between initializing a string with (char *)malloc(0) and NULL
Do not use malloc(0) in this case, as a NULL check on the pointer may fail, giving the wrong impression of a valid allocation of the memory to the pointer. Always use NULL for initialization.
The above code invokes undefined behavior. You have allocated insufficient memory and you are accessing invalid addresses.
According to the specifications, malloc(0) will return either "a null pointer or a unique pointer that can be successfully passed to free()".
malloc definition:
Allocates a block of size bytes of memory, returning a pointer to the
beginning of the block.
The content of the newly allocated block of memory is not initialized,
remaining with indeterminate values.
If size is zero, the return value depends on the particular library
implementation (it may or may not be a null pointer), but the returned
pointer shall not be dereferenced.
Taken from here and found this related question.

Problem with C pointers in 2d char arrays

Why does this work:
//split returns (char**)
char *temp2;
temp2=split(array[i],'=')[1];
and this doesn't:
char **temps;
temps[0]=temp2; //crashes
or this:
temps[0]=split(array[i],'=')[1]; //crashes
temps is just a pointer to a char*, but it has no initalized, sensible value! temps[0] is equivalent to *(temps + 0), but you cannot dereference a garbage value -- you first have to make temps points somewhere useful, e.g. by allocating memory for it.
If you want to store some char*s with automatic storage, then declare an array of char pointers instead:
char * temps[20];
temps[0] = /*... etc. ...*/
Split returns a pointer to a pointer to a char. So, what is returned from split(array[i],'=')[1] is a pointer to char which is what you declared on the stack and thus reserved space for it. That is why it works.
The other two don't work because the space pointed to is not allocated. You should use malloc().
If you simply declare a pointer variable:
char **temps;
It's not really pointing to somewhere. Well, it actually is, but that's probably garbage (anywhere in memory). You have to initialize it before using it. Try allocating space for it.
char **temps was never allocated any space. You're dereferencing bad memory with temps[0].
man malloc()
You have to allocate your memory to get space!
char **temps;
temps[0]=temp2; //crashes
The pointer, temps, is uninitialized. Dereferencing it is an undefined operation.
Because temps isn't initialized. It's a random value pointing to a random memory location.
Think of it this way:
char *temp2 = "foo";
char **temps;
temps[0] = temp2; // won't work
temps = &temp2; // ok
temp2 points at a C string. You can point temps at the address of temp2, (&temp2) but you can't dereference temps (that is, temps[0]) unless you first make it point at something valid. From your question it sounds like you want to malloc() an array of char* first.
In the second and third cases, you are dereferencing temps[0] without first making it refer to some valid memory location. As has been pointed out, temps is pointing at a garbage location.
Your first case works because you're dereferencing split(), so it's giving you a char*.

Resources