Linked Lists in C, last node point to NULL? - c

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.

Related

Can I realloc() an unallocated pointer?

Normally, realloc() is used to reallocate a previously allocated pointer:
int *DynamicArray = malloc(sizeof(int)*SomeArbitraryValue);
// Some rando code where DynamicArray is used
DynamicArray = realloc(DynamicArray, sizeof(int)*SomeOtherArbitraryValue)
But can realloc() be used to directly allocate memory? As in
int *DynamicArray = realloc(/*...*/);
Can realloc() handle non-preallocated pointers?
Yes, just pass NULL to it's first argument.
The manpage of realloc(3) says ...
The realloc() function changes the size of the memory block pointed to by ptr to size bytes. The contents will be unchanged in the range from the start of the region up to the minimum of the old and new sizes. If the new size is larger than the old size, the added memory will not be initialized. If ptr is NULL, then the call is equivalent to malloc(size), for all values of size; if size is equal to zero, and ptr is not NULL, then the call is equivalent to free(ptr). Unless ptr is NULL, it must have been returned by an
earlier call to malloc(), calloc(), or realloc(). If the area pointed to was moved, a free(ptr) is done.
As the answer by #ZhangBoyang tells you, yes, assuming one possible interpretation of your question. However the way you've worded your question ("non-preallocated pointers") suggests you may have misunderstanding of some of the concepts involved. malloc does not "allocate pointers". It allocates objects, and pointers are values that point to objects. The lifetime of those objects are not connected to the lifetime of any particular pointer pointing to them.
Passing a pointer to realloc doesn't "do anything to" the pointer. It does something to the object pointed to by it. If the pointer is uninitialized or invalid, the call has undefined behavior and bad things will happen. If the pointer is a null pointer, however, realloc(ptr, n) will behave exactly as malloc(n).

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.

Is assinging NULL to a pointer bad programming?

if I initialize a pointer with NULL, is that wrong? What problems do i face? Or it's simply bad programming?
int a,b,*ptr;
ptr = NULL;
ptr=&a;
Is there any problem with the above lines??
In the code that you provided the assignment of NULL is useless, because the pointer is never accessed between the two assignments (i.e. assigning a NULL and an assignment of &a). However, there are other situations when assigning NULL to a pointer is very desirable:
If an assignment of a memory location to a pointer happens conditionally, and then the pointer is passed to free at the end, you need to assign NULL to the pointer at initialization
When a pointer is deallocated with free, but remains visible for some additional time, you should set the pointer to NULL after freeing it to avoid dangling references
When a situation can arise when a pointer is accessed after becoming invalid, you need to assign NULL to the pointer so that your program fails as fast as possible.

C - functions that return pointers, how to write efficient code?

If I had a function defined arbitrarily like:
char* myfunction(int, int[]);
which, as shown, returns a character pointer. Do you have to write in the calling function something like:
char *ptr = myfunction( ... );
Or is there a way to use the pointer that is returned by the function without creating another pointer to the one returned?
I ask because, given how I described above, you essentially have a pointer returned, and another pointer assigned to that one. Thus, you then have an unused pointer (the one returned by the function) taking up memory.
If there is no way to explicitly use the pointer that is returned, is there a way to assign a new pointer to the returned pointer and free the unused one?
A pointer is a really small thing. It's just a representation of the address of an object. You shouldn't be concerned about creating extra copies of a pointer (it's like creating an extra int).
char* foo() {
char* bar;
// some stuff that mallocs a value and assigns to bar
return bar;
}
char* x = foo();
In the simplified example above, the bar pointer is created on the stack, and the code in the comments points it at some memory in the heap (with a Malloc or something). When the function foo() is evaluated, the value of the pointer (e.g. The address of the memory) is popped off the stack and assigned to x. There is no unused pointer hanging around, it's just been reassigned. The memory that it points to remains exactly where it is and isn't duplicated.
You aren't creating extra copies of the memory that the pointer is pointing to. In fact, that's a large reason to pref pointers, because it involves copying less.
The pointer that is returned by the function doesn't waste memory as you state. When the function returns, and as soon as the affectation ptr = myfunction(...); is done, the returned value doesn't exist anymore in memory.
But to answer your question, yes you can use the returned pointer directly, without a temporary variable. Although it is a rvalue (you can't do myfunction() = NULL for example), the location it's pointing to is at your disposal : *myfunction() = 3 is valid, granted the pointer returned is valid.
I prefer using a temporary variable, as you can reuse the value in 2 or more expressions, and it is far more readable in my opinion.

Pointer pointing to an empty array

I have a pointer that is pointing to the start of an array, but I need to check that it is unallocated. I thought of dereferencing the pointer and checking if NULL but that leads to a type error. Can anyone see what I'm doing wrong?
int mydispose(int *array){
int i = 0;
if(*array == NULL){
return 1;
}
return ;
}
EDIT: Sorry if I was unclear: I have a pointer that points to the start of an array, but I wish to check whether the array is empty.
*array == NULL is wrong. You are dereferencing the pointer first (which could lead to a segfault if the pointer really is null) and then comparing its int value to a pointer value. Moreover, your compiler will perfectly accept that erroneous expression if NULL is defined as just 0 and not (void *) 0.
You should be checking array == NULL to see if the passed pointer refers to anything, and then dereference it only in case it's not NULL.
Be aware, however, that dereferencing a non-null pointer isn't guaranteed to be a safe operation either. If the pointer contains a garbage value because it was allocated on the stack and not initialized, or if it refers to a deallocated region of memory, nasty bugs can happen.
You want if (array == NULL) -- but unless you first initialize array to NULL, it won't do any good either. I think you'd be better off backing up and telling us a bit more about what you're trying to accomplish, and trying to get help trying to accomplish your overall goal.
The only safe way to determine the allocation status of *array is to:
Make sure *array is set to NULL is not allocated. int *array = NULL;
Check if the array is NULL: if (array == NULL) return -1;
You can't reliably check if some memory location is allocated. *array is not a valid code, because it's the same as array[0], but array[0] is not allocated. Non-allocated memory location can contain any value.
The only option is to ensure that you get the information whether the array is allocated alongside with your array. A popular option is representing unallocated array as NULL, but you may choose other option as well.
By the way, there is a difference between an empty array (that is, array of size 0), and array which is not allocated at all. The first option occurs when you use malloc(0), the second when your pointer is not initialized at all. For malloc(0) it's allowed to return NULL, but it's allowed to return a non-NULL pointer (which you however can't dereference) as well. Both ways are valid according to the standard.
The immediate problem with your code is that you dereferencing array before comparing it to NULL. The type of the expression *array is int, not int *. Leave off the dereference operator and the types will match:
if (array == NULL) {...}
Note that an uninitialized pointer is only guaranteed to contain NULL if it was declared with static extent (i.e. it was either declared at file scope or with the static keyword in front of it). Similarly, calling free on a pointer won't set that pointer value to NULL; it will contain the same pointer value as before, but it will now be invalid.
You must use it like this:
if(array == NULL) ...

Resources