Pointer pointing to an empty array - c

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) ...

Related

How does malloc() know you want to use the block of memory it supplies as an array?

If malloc() returns a pointer to a single block of memory, how can it be used to store multiple values contiguously and allow access to each one using the subscript operator, acting as a pointer to an array?
If I were to try and change the "second element" of an integer by subscripting its address, it would cause undefined behaviour. As malloc() returns the pointer to a single block of memory, shouldn't the pointer it returns refer to the entire block, and thus subscripting it should access the garbage value next to it in memory?
Furthermore, the allocated memory can also be used to store a single value, but only up to the size of the type the pointer is cast to, not to that of the allocated block of memory.
Is all this something to do with the type the pointer is cast to after being returned? Could someone point me in the right direction?
I think your misunderstanding is here:
As malloc() returns the pointer to a single block of memory, shouldn't the pointer it returns refer to the entire block, and thus subscripting it should access the garbage value next to it in memory?
Indeed if you do p = malloc(n) and p has type "pointer to some type of size n", then p[1] is an out-of-bounds array access. However, normally when you do p = malloc(n) to allocate an array, the type of p is not a pointer to the array (of size n), but a pointer to the first element of the array. That is, instead of
char (*p)[500] = malloc(500);
you do:
char *p = malloc(500);
and in this case p[1] is perfectly valid. Note that with the first, unusual, form, you could still do (*p)[1] or p[0][1] and have it be valid.
But be careful, if you use malloc several times it will return memory allocated in different parts of heap. So you can't move around from one array to another.

Is my Array of Int* all Initialized to NULL?

I'm a Java programmer struggling to understand C pointers and arrays. (FULL DISCLOSURE: I'm also a CS student, and yes, this question helps me with a programming assignment.)
I'm trying to create an array of int* pointers, then ensure that every pointer is NULL. Later, this will come into play when I need to look up data in the array; whether there is a valid int or a NULL in a given spot will be important.
So allocating the space for the array is easy, but how to set all those pointers to NULL? Here's my less-than-stellar attempt:
#include<stdio.h>
#include<stdlib.h>
#define TABLESIZE 10
int main(int argc, char *argv[]){
int* table = (int*) malloc(TABLESIZE * sizeof(int));
// Initialize all *int pointers to NULL
int i;
for(i=0; i<TABLESIZE; i++){
if((table+i)!=NULL){ // They may be NULL already? I don't know...
*(table+i) = NULL; // This generates a warning:
// "warning: assignment makes integer from pointer without a cast [-Wint-conversion]"
}
}
// Sanity check : are all int* are NULL ?
for(i=0; i<TABLESIZE; i++){
printf("%d: %p %d ", i, (table+i), *(table+i));
if((table+i) == NULL)
printf("(NULL)");
printf("\n");
}
free(table);
return 1;
}
Output is:
$ ./a.exe
0: 0x6000103c0 0
1: 0x6000103c4 0
2: 0x6000103c8 0
3: 0x6000103cc 0
4: 0x6000103d0 0
5: 0x6000103d4 0
6: 0x6000103d8 0
7: 0x6000103dc 0
8: 0x6000103e0 0
9: 0x6000103e4 0
$
So I'll be flat-out honest... I don't know what the above tells me. I'm guessing that I've created a 1D array where all the values in the array are valid ints, all 0.
But this is problematic for later in my program. When it comes time for my code to insert data into table[x], the code must be able to look at the array and know if another valid int was previously inserted in the same spot. If it sees table[x] = 0, does it conclude a 0 was inserted into index x, or that the spot is available?
I liked the idea of using an array of pointers to ints because that would neatly solve this problem. If my code saw:
table[x] --> NULL // This spot is empty and available
table[x] --> 0 // This spot is occupied, can't insert here
But I don't think I'm coding what I want.
Any thought/advice/comments/criticism is greatly appreciated.
Thanks!
-Pete
int* table = malloc(TABLESIZE * sizeof(int));
Does not create an array of pointers, rather it creates a single int pointer to the start of block of allocated memory of size (TABLESIZE * sizeof(int))
The reason you are getting an error is that an int* is just that; a pointer to an int.
The * operator is called the 'dereference' operator. Its job when placed before a variable is to say 'go to wherever this pointer is pointing'. Therefore, the line
*(table+i) = NULL;
Means 'go to wherever table is pointing, move along i * sizeof(int), then set that particular int to NULL. This obviously doesn't make sense - you can't set a an int to NULL, as that's a pointer value. Hence your error.
By the way, since pointers can also be treated like arrays in C, the above line is also the exact equivalent of
table[i] = NULL;
If you want your initial malloc to be an array of pointers you need to allocate space not for int but for int*, so you could do
int** table = malloc(TABLESIZE * sizeof(int*));
Then you have an int** (Double pointer - aka a pointer to a pointer) referencing a block of TABLESIZE int*'s
Once you have done this, the code below that line will correctly set your pointers to NULL. To then achieve the table as described in your question, you will need to do a further malloc for each cell before you put an int in it. So for example to put '3' into cell 2
if(*(table + 2) == NULL) {
*(table + 2) = malloc(sizeof(int));
}
**(table + 2) = 3;
Note the double deference on the last line: 'Go to wherever table is pointing, move along 2 * sizeof(int*), then go to wherever that pointer is pointing.' Again, this can also be achieved with array syntax
if(table[2] == NULL) {
table[2] = malloc(sizeof(int));
}
*table[2] = 3;
Be careful not to call malloc() on the same cell twice; if you do this you will have a memory leak.
I'm a Java programmer struggling to understand C pointers and arrays.
Yes, the "struggling" part is evident in your code.
A C array is simply an ordered collection of elements of a specified type, arranged contiguously in memory. This is similar to a Java array, but Java provides no means for you to see or probe the arrangement of the elements in memory, and its arrays have additional data associated with them (in particular, they know their own lengths).
A C pointer is a value that represents the address of some other object, where "object" means a stored value of any type, including built-in (Java: "primitive") types, aggregate types (structures and arrays), pointer types, and even no particular type. This is similar in some ways to a Java "reference", which is reflected in the fact that Java raises "NullPointerException" if it tries to dereference a null reference.
It is very important to understand that although there is a close relationship between arrays and pointers, they are not at all the same thing. That should be clear from the descriptions above, but I regularly come across clueless claims to the contrary.
It is also important to understand that pointer values can be invalid -- not pointing to any object. You can easily have a pointer value, maybe stored in a variable or an array, whose value is garbage. This is something to manage, not to be afraid of.
Furthermore, it is important to understand that pointer values do not necessarily have to be obtained via memory allocation functions. They can also be obtained via the address-of operator (&) or through evaluation of an expression involving an array, or garbage pointer values can spring up naturally when a pointer is declared but not initialized.
I'm trying to create an array of int* pointers
I'm not sure whether you mean an array whose elements have type int * (pointer to int), an array whose elements have type int ** (pointer to pointer to int), or maybe an array whose elements have type int. My guess from your wording would be the first, reading you literally yields the second, and your actual code presents something like the third.
This would be the declaration of an array of int *:
int *table[TABLESIZE];
Not having specified an initializer, you cannot rely on any particular values for the elements until you assign values. Code similar to what you presented could be used for that (less the NULL check, which has undefined behavior on account of the initial values being indeterminate, and anyway would provide no advantage whatever), but I'd be inclined to write it slightly differently:
for (int i = 0; i < TABLESIZE; i++) {
table[i] = NULL;
}
At this point, the elements of your table are all initialized with the one pointer value that you can be certain does not point to any object. You can check those pointer values, but you must not dereference them:
// Sanity check : are all int* are NULL ?
for(int i = 0; i < TABLESIZE; i++) {
printf("%d: %p ", i, (void *) table[i]);
if(table[i] == NULL)
printf("(NULL)");
printf("\n");
}
I liked the idea of using an array of pointers to ints because that
would neatly solve this problem. If my code saw:
table[x] --> NULL // This spot is empty and available
table[x] --> 0 // This spot is occupied, can't insert here
That does not make sense, because 0 interpreted as a value of any pointer type is a null pointer constant. However, having started by assigning all elements of the table to be NULL, if you intend to set elements to valid pointers when you assign them, then you can check for NULL to see whether a spot is available, since NULL is never a pointer to an object.
Do note, by the way, that if you declare table as a bona fide array, as above, then you do not need to free it. You might, however, need to free some or all of the objects to which its elements point, depending on whether those objects were dynamically allocated, and on whether they have been or will be freed by other means.
In both C and Java, int holds an integer value. There is no additional, distinguishable null state. Usually, every possible bit-pattern for an int represents a distinct integer value, so it is not physically possible to store this extra state.
If you want to implement something that can be "either 'null' or any possible value in the range of int" then you will have to use additional storage for each array entry. (For example, you could maintain a parallel set of boolean flags indicating whether each entry is "active" or not).
An alternative solution would be to reserve one particular integer value to represent that that array entry should be considered "empty". This technique is called sentinel value.
In Java you can have an array of Integer , which is an array of references that may either be "null" or refer to an int stored elsewhere (the language manages the allocation behind the scenes). To simulate that memory layout in C
the code would be:
// Allocate array and initialize all entries to NULL
int * array[ARRAYSIZE] = { NULL };
// Insert at position (repeatable)
if ( array[2] == NULL )
array[2] = malloc( sizeof(int) );
*array[2] = 10;
// Use item
printf("%d\n", *array[2]);
// Remove from position
free( array[2] );
array[2] = NULL;
To avoid memory leaks you will need to remember to loop through and do the removal procedure before array goes out of scope. It would also be good to check for malloc failure and abort the program or take some other action.
Note that this technique would be considered unusual in C, and not space-efficient compared to the other available options.

Is it common practice to memset reallocated memory to 0?

In a C book I found in an example for implementing a dynamically resizing array this code (simplified):
void *contents = realloc(array->contents, array->max * sizeof(void *));
array->contents = contents;
memset(array->contents + old_max, 0, array->expand_rate + 1);
Source: Learn C The Hard Way – Chapter 34
I was a bit surprised what memset is supposed to achieve here, but then I understood it's used in order to "zero out" the reallocated memory.
I googled in order to find out, if this is what I'm supposed to do after a realloc and found a stackoverflow answer regarding this:
There is probably no need to do the memset […]
But, even if you wanted to "zero it out so everything is nice", or really need the new pointers to be NULL: the C standard doesn't guarantee that all-bits-zero is the null pointer constant (i.e., NULL), so memset() isn't the right solution anyway.
Source: How to zero out new memory after realloc
The suggested solution instead of memset is then to use a for loop in order to set the memory to NULL.
So my question is, as memset does not necessarily mean setting values to NULL and the for loop solution seems a bit tedious – is it really needed to set the newly allocated memory?
So my question is, as memset does not necessarily mean setting values
to NULL and the for loop solution seems a bit tedious – is it really
needed to set the newly allocated memory?
realloc doesn't initialize values of the newly allocated memory segment.
So it is needed to initialize the memory if you are planning to read values of that (uninitialized) memory. Because reading values from that uninitialized memory will trigger undefined behaviour.
By the way, safe way to use realloc (since it can fail) is:
// Since using realloc with size of 0 is tricky and useless probably
// we use below check (from discussion with #chux)
if (new_size == 0)
dosmth();
else
{
new_p = realloc(p, new_size);
if (new_p == NULL)
{
// ...handle error
}else
{
p = new_p;
}
}
Setting a void * to 0 is a value that will compare equal to NULL. Likely memset(ptr, 0, size) is OK - but need to see more code for certainty.
OTOH: is the code correct? Maybe should be
// memset(array->contents + old_max, 0, array->expand_rate + 1);
memset(array->contents + old_max, 0, sizeof(void *) * (array->expand_rate + 1) );
This is wrong:
But, even if you wanted to "zero it out so everything is nice", or
really need the new pointers to be NULL: the C standard doesn't
guarantee that all-bits-zero is the null pointer constant (i.e.,
NULL), so memset() isn't the right solution anyway.
The C standard does in fact guarantee exactly that.
Per section 6.3.2.3 of the C standard:
An integer constant expression with the value 0, or such an expression
cast to type void *, is called a null pointer constant. If a null
pointer constant is converted to a pointer type, the resulting
pointer, called a null pointer, is guaranteed to compare unequal to
a pointer to any object or function.
Conversion of a null pointer to another pointer type yields a null
pointer of that type. Any two null pointers shall compare equal.
Note that a pointer with a value of zero is a null pointer. That doesn't mean NULL itself has to be zero. But also note that "any two null pointers shall compare equal". So any null pointer is equal to the NULL value.
Since memset() takes as its second argument an integer value, passing a zero integer value to memset() will produce null pointers. Because the value passed to memset() is "[a]n integer constant expression with the value 0", per 6.3.2.3.

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.

Resources