Why give a variable a null value when declaring it? - c

I noticed that many times when declaring variables/arrays/etc, people give it a null value or 0.
for example, take a look at the following snippet:
int nNum = 0;
char cBuffer[10] = { 0 };
int *nPointer = NULL;
and etc.
Untill asking this question I figured it would be for debugging purposes, since when I
was debugging a program with Visual Studio I noticed that variables that had no value had
undefined numbers as their value, whilst with 0 they had... 0.

There are a number of reasons to initialize variables to 0 or NULL.
First of all, remember that unless it's declared at file scope (outside of any function) or with the static keyword, a variable will contain an indeterminate value; it may be 0, it may be 0xDEADBEEF, it may be something else.
For sums, counters, and the like, you want to make sure you start from 0, otherwise you will get an invalid result:
int sum = 0;
while ( not_at_end_of_things_to_sum )
sum += next_thing_to_sum;
int count = 0;
while ( there_is_another_thing_to_count )
count++;
etc.
Granted, you don't have to initialize these kinds of variables as part of the declaration; you just want to make sure they're zeroed out before you use them, so you could write
int count;
...
count = 0;
while ( there_is_another_thing_to_count )
count++;
it's just that by doing it as part of the declaration, you don't have to worry about it later.
For arrays intended to hold strings, it's to make sure that there's a 0 terminator if you're building a string without using strcpy or strcat or scanf or similar:
char buf[N] = { 0 }; // first element is *explicitly* initialized to 0,
// remaining elements are *implicitly* initialized to 0
while ( not_at_end_of_input && i < N - 1 )
buf[i++] = next_char;
You don't have to do it this way, but otherwise you'd have to be sure to add the 0 terminator manually:
buf[i] = 0;
For pointers, it's to make it easy to test if a pointer is valid or not. A NULL pointer is a well-defined invalid pointer value that's easy to test against:
char *p = NULL;
...
if ( !p ) // or p == NULL )
{
// p has not yet been assigned or allocated
p = malloc( ... );
}
Otherwise, it's effectively impossible to tell if the pointer value is valid (points to an object or memory allocated with malloc) or not.

An uninitialized pointer variable may contain a garbage value. The purpose of initializing a pointer with NULL is that if you inadvertently use it without assigning a proper address, you do not end up modifying the contents at a random memory address.

Depending on the language, you would use NULL or just int *nPointer;
it's called initializing a variable, i.e. you're creating it. This is extremely helpful if you want your program to remain at a constant state, knowing that "un-initialized" variables won't cause an exception.
If you're inializing a varibale inside a loop or function, and you want to use it outside that loop/function and the loop/function only executes when there's a condition attached to it e.g:
if(nNum != 0){
int *nPointer = NULL;
for(int i=0; i<10; i++){
*nPointer++;
}
}
In this case if you did not initialize your variable, and you try and use it later down the line, your program might break. However, if it has been initialized, your safe, knowing it exists, but is still NULL.
SAFER CODE:
int *nPointer = NULL; //Or this will be a class member
if(nNum != 0){
for(int i=0; i<10; i++){
*nPointer++;
}
}

Related

Initialize an array in a loop (array vs malloc)

Hi I am quite new to C and I have a question about the behavior of array initialization using [] and malloc.
int main() {
int* pointer;
for(int i = 0; i < 100; i++) {
// Init the Array
int tmp[2] = {};
// Do some operation here...
tmp[0] = 0;
tmp[1] = i;
// If the value is 1, copy that array pointer
if(i == 1) {
pointer = tmp;
}
}
// expected 1 here, but got 99
printf("%d\n", pointer[1]);
return 0;
}
Why is the output 99? I thought the array is re-inited every loop, but it turns out using the same memory address. And if I use malloc to init the array instead, the result becomes 1 as expected.
Is there any way I could get result 1 without using malloc?
Your code is invalid as you access the variable which is out of the scope using the reference. It is undefined behaviour.
Every time you assign the i to the same element to the array. Pointer only references (points to) the first element of this array. So if you change the underlaying object the value you get using the reference will change as well. If your finger is pointing to the box of 5 apples and someone eats 2 apples, your finger will point to the box of 3 apples, not 5.
You need to make a copy of the object.
if(i == 1) {
pointer = malloc(sizeof(tmp));
memcpy(pointer, tmp, sizeof(tmp));
}
or break the loop (declaring it static or moving the tmp out of the for loop scope)
for(int i = 0; i < 100; i++) {
// Init the Array
static int tmp[2];
// Do some operation here...
tmp[0] = 0;
tmp[1] = i;
// If the value is 1, copy that array pointer
if(i == 1) {
pointer = tmp;
break;
}
}
The scope of the array tmp is the block scope of the for loop
for(int i = 0; i < 100; i++) {
// Init the Array
int tmp[2] = {};
// Do some operation here...
tmp[0] = 0;
tmp[1] = i;
// If the value is 1, copy that array pointer
if(i == 1) {
pointer = tmp;
}
}
That is in each iteration of the loop a new array tmp is created and ceases to be alive after exiting the block.
Thus the pointer pointer is invalid after the for loop. Dereferencing the pointer after the for loop invokes undefined behavior.
You have gotten the result 99 only because the array tmp was not being reallocated and the memory occupied by the array was not yet overwritten. So the last value stored in this extent of memory that is the value of i equal to 99 was outputted.
Even if you will declare the array tmp before the for loop then using the pointer pointer you will get as the output the value 99 that is the value last stored in the array.
You could write for example
int tmp[2] = { 0 };
int *pointer = tmp;
for(int i = 0; i < 100; i++) {
// Do some operation here...
tmp[0] = 0;
tmp[1] = i;
}
And the last value stored in the array (when i is equal to 99)
tmp[1] = i;
will be outputted in this call
printf("%d\n", pointer[1]);
Pay attention to that such an initialization with empty braces is invalid in C opposite to C++
int tmp[2] = {};
You need to write at least like
int tmp[2] = { 0 };
As we know pointer stores a memory address.
Here, I think when you give the command: pointer = tmp;,
the address of the array stored in 'tmp' is copied to the 'pointer'.
But when the loop of i = 1 gets completed, the array that you created in that particular loop and the pointer 'tmp' gets forgotten.
Then the loop for i=2 starts, 'tmp' and the array gets created again.
It happens again till the loop end.
I think that the program is storing tmp[1] at the same location every time due to which the data stored at that changes again and again.
So, when you give the command printf("%d\n", pointer[1]);, the data at that address get printed which is no longer equal to 1, it has changed.
The mistake is that we shared the address of 'tmp' with the 'pointer'.
But when we use malloc, we lock that memory means other programs can't use that memory. ( That's why we always need to free that memory to avoid memory leaks ).
It's the reason while using malloc you get output as 1 as your other commands can't touch that particular memory.
Solution:
If you want to solve the problem without malloc.
Initialise 'pointer' as an array to store data of 'tmp'.
use this code,
pointer[0] = tmp[0]; pointer[1] = tmp[1];
at place of
pointer = tmp;.
Now, you will not be copying addresses to 'pointer' but the data in the 'tmp'.
And if you have a big array with many values in it, just use it for loop.
solution image
Also, you will get the same problem if you do it like this, all because of copying only the address, you will be doing the same thing.
Maybe you can relate,same problem image
Thanks.

if statements in c with NULL

I have a program that looks something like this:
int someVal = 5;
int startCol = NULL;
int startRow = NULL;
int destCol = NULL;
int destRow = NULL;
for (int i = 0;i<2;i++){
if (startCol == NULL){
startCol = someVal;
}
// same for other variables
}
so basically i want to change the value of the variables at the first time it is being checked but not after.
how can i do that? in python i would use None but it appears i can't use NULL with int. I can't just set the values to 0 because i use them after for array indexes so if the value is 0 i will access the first value but i don't want to.
NULL when assigned to the integer converts to zero.
int variables do not have any special value which means "not initialized" or "no value".
The only workaround is to choose one integer value which will indicate that variable needs initialization. You can also define more complex data types holding the information about needed initialization
typedef struct
{
bool initialized;
int val;
}myInt_t;
myInt_t x = {.initialized = false};
if (!x.initilaized) x.val = 100;
But the best way is to have correct program algorithm and to program carefully, remembering about not initialized variables.
If you are using them for indices, setting them to -1 isn't a bad idea.
Then you will have only to check if they are -1.
NULL is ((void*)0). It is a pointer. Mixing int and pointer isn't really the best practice but produces the desired output if it is used well.
If you are using the code from the snippet, isn't it an option to just check if i == 0?
NULL is for pointers.
ints are just int values and not references. You can assign them to NULL and test if they are NULL but NULL is just a number (if used as int (I think it is 0).
If you use it as a pointer, it will point to an address that is not available (dereferenceing it will cause a SEGENV) and you can use it in order to not assign any data with it.

printing strings produces garbage even when (I think) they are null terminated

When I run print_puzzle(create_puzzle(input)), I get a bunch of gobbledegook at the bottom of the output, only in the last row. I have no idea why this keeps happening. The output is supposed to be 9 rows of 9 numbers (the input is a sudoku puzzle with zeroes representing empty spaces).
This bunch of code should take that input, make a 2d array of strings and then, with print_puzzle, print those strings out in a grid. They are string because eventually I will implement a way to display all the values the square could possibly be. But for now, when I print it out, things are screwed up. I even tried putting the null value in every single element of all 81 strings but it still get's screwed up when it goes to print the strings. I'm lost!
typedef struct square {
char vals[10]; // string of possible values
} square_t;
typedef struct puzzle {
square_t squares[9][9];
} puzzle_t;
static puzzle_t *create_puzzle(unsigned char vals[9][9]) {
puzzle_t puz;
puzzle_t *p = &puz;
int i, j, k, valnum;
for (i = 0; i < 9; i++) {
for (j = 0; j < 9; j++) {
puz.squares[i][j].vals[0] = '\0';
puz.squares[i][j].vals[1] = '\0';
puz.squares[i][j].vals[2] = '\0';
puz.squares[i][j].vals[3] = '\0';
puz.squares[i][j].vals[4] = '\0';
puz.squares[i][j].vals[5] = '\0';
puz.squares[i][j].vals[6] = '\0';
puz.squares[i][j].vals[7] = '\0';
puz.squares[i][j].vals[8] = '\0';
puz.squares[i][j].vals[9] = '\0';
valnum = vals[i][j] -'0';
for (k = 0; k < 10; k++){
if ((char)(k + '0') == (char)(valnum + '0')){
char tmpStr[2] = {(char)(valnum +'0'),'\0'};
strcat(puz.squares[i][j].vals, tmpStr);
}
}
}
}
return p;
}
void print_puzzle(puzzle_t *p) {
int i, j;
for (i=0; i<9; i++) {
for (j=0; j<9; j++) {
printf(" %2s", p->squares[i][j].vals);
}
printf("\n");
}
}
In short:
In function create_puzzle(), you are returning a pointer to the local variable puz. Local variables are only known to function inside their own. So the content referenced by the pointer returned by create_puzzle is indeterminate.
More details:
In C++, local variables are usually generated as storage on a "stack" data structure. when create_puzzle() method is entered, its local variables come alive. A function's local variables will be dead when the method is over. An implementation of C++ is not required to leave the garbage you left on the stack untouched so that you can access it's original content. C++ is not a safe language, implementations let you make mistake and get away with it. Other memory-safe languages solve this problem by restricting your power. For example in C# you can take the address of a local, but the language is cleverly designed so that it is impossible to use it after the lifetime of the local ends.
This answer is very awesome:
Can a local variable's memory be accessed outside its scope?
In function create_puzzle(), you are returning a pointer of the type puzzle_t. But, the address of variable puz of the type puzzle_t is invalid once you return from the function.
Variables that are declared inside a function are local variables. They can be used only by statements that are inside that function. These Local variables are not known to functions outside their own, so returning an address of a local variable doesn't make sense as when the function returns, the local storage it was using on the stack is considered invalid by the program, though it may not get cleared right away. Logically, the value at puz is indeterminate, and accessing it results in undefined behavior.
You can make puz a global variable, and use it the way you are doing right now.
You are returning a local variable here:
return p;
Declare p and puz outside of the function, then it should work.
p point to local memory that is unavailable after the function ends. Returning that leads to problems. Instead allocate memory.
// puzzle_t puz;
// puzzle_t *p = &puz;
puzzle_t *p = malloc(sizeof *p);
assert(p);
Be sure to free() the memory after the calling code completes using it.

C using malloc and duplicating array

I am supposed to follow the following criteria:
Implement function answer4 (pointer parameter and n):
Prepare an array of student_record using malloc() of n items.
Duplicate the student record from the parameter to the array n
times.
Return the array.
And I came with the code below, but it's obviously not correct. What's the correct way to implement this?
student_record *answer4(student_record* p, unsigned int n)
{
int i;
student_record* q = malloc(sizeof(student_record)*n);
for(i = 0; i < n ; i++){
q[i] = p[i];
}
free(q);
return q;
};
p = malloc(sizeof(student_record)*n);
This is problematic: you're overwriting the p input argument, so you can't reference the data you were handed after that line.
Which means that your inner loop reads initialized data.
This:
return a;
is problematic too - it would return a pointer to a local variable, and that's not good - that pointer becomes invalid as soon as the function returns.
What you need is something like:
student_record* ret = malloc(...);
for (int i=...) {
// copy p[i] to ret[i]
}
return ret;
1) You reassigned p, the array you were suppose to copy, by calling malloc().
2) You can't return the address of a local stack variable (a). Change a to a pointer, malloc it to the size of p, and copy p into. Malloc'd memory is heap memory, and so you can return such an address.
a[] is a local automatic array. Once you return from the function, it is erased from memory, so the calling function can't use the array you returned.
What you probably wanted to do is to malloc a new array (ie, not p), into which you should assign the duplicates and return its values w/o freeing the malloced memory.
Try to use better names, it might help in avoiding the obvious mix-up errors you have in your code.
For instance, start the function with:
student_record * answer4(const student_record *template, size_t n)
{
...
}
It also makes the code clearer. Note that I added const to make it clearer that the first argument is input-only, and made the type of the second one size_t which is good when dealing with "counts" and sizes of things.
The code in this question is evolving quite quickly but at the time of this answer it contains these two lines:
free(q);
return q;
This is guaranteed to be wrong - after the call to free its argument points to invalid memory and anything could happen subsequently upon using the value of q. i.e. you're returning an invalid pointer. Since you're returning q, don't free it yet! It becomes a "caller-owned" variable and it becomes the caller's responsibility to free it.
student_record* answer4(student_record* p, unsigned int n)
{
uint8_t *data, *pos;
size_t size = sizeof(student_record);
data = malloc(size*n);
pos = data;
for(unsigned int i = 0; i < n ; i++, pos=&pos[size])
memcpy(pos,p,size);
return (student_record *)data;
};
You may do like this.
This compiles and, I think, does what you want:
student_record *answer4(const student_record *const p, const unsigned int n)
{
unsigned int i;
student_record *const a = malloc(sizeof(student_record)*n);
for(i = 0; i < n; ++i)
{
a[i] = p[i];
}
return a;
};
Several points:
The existing array is identified as p. You want to copy from it. You probably do not want to free it (to free it is probably the caller's job).
The new array is a. You want to copy to it. The function cannot free it, because the caller will need it. Therefore, the caller must take the responsibility to free it, once the caller has done with it.
The array has n elements, indexed 0 through n-1. The usual way to express the upper bound on the index thus is i < n.
The consts I have added are not required, but well-written code will probably include them.
Altought, there are previous GOOD answers to this question, I couldn't avoid added my own. Since I got pascal programming in Collegue, I am used to do this, in C related programming languages:
void* AnyFunction(int AnyParameter)
{
void* Result = NULL;
DoSomethingWith(Result);
return Result;
}
This, helps me to easy debug, and avoid bugs like the one mention by #ysap, related to pointers.
Something important to remember, is that the question mention to return a SINGLE pointer, this a common caveat, because a pointer, can be used to address a single item, or a consecutive array !!!
This question suggests to use an array as A CONCEPT, with pointers, NOT USING ARRAY SYNTAX.
// returns a single pointer to an array:
student_record* answer4(student_record* student, unsigned int n)
{
// empty result variable for this function:
student_record* Result = NULL;
// the result will allocate a conceptual array, even if it is a single pointer:
student_record* Result = malloc(sizeof(student_record)*n);
// a copy of the destination result, will move for each item
student_record* dest = Result;
int i;
for(i = 0; i < n ; i++){
// copy contents, not address:
*dest = *student;
// move to next item of "Result"
dest++;
}
// the data referenced by "Result", was changed using "dest"
return Result;
} // student_record* answer4(...)
Check that, there is not subscript operator here, because of addressing with pointers.
Please, don't start a pascal v.s. c flame war, this is just a suggestion.

How can I tell if a multi dimensional array has not been assigned to?

If I have two arrays likes this:
short** x;
short** y = functionThatReturnsAnArray();
In this situation sizeof(x) == sizeof(y).
Both are 4, I believe that this is because the outer array is simply an array of pointers and therefore doesn't actually have any RAM allocated to it.
How can I find out that x has not been assigned a value?
Thanks,
Joe
From a comment in your original post, what you mean is whether you can tell if a value has been assigned to a variable. We call that initialization. When a value hasn't been stored to a variable it's uninitialized, and that's bad, because you never know what might be in there, and no, you cannot check whether it has been initialized, so initialize it when you declare it.
sizeof(x) == sizeof(y) because they're declared as the same type (short**); their contents don't matter (sizeof is actually determined by the compiler, so it often can't know what's in it).
If you want to know whether the memory areas that each point to are zero, you'll need to do it manually (and you need to know how long each array is):
int x_empty = 1;
for(int i = 0; i < x_length_d1 && x_empty; i++) {
if(x[i] == NULL) {
// Handle a missing row however you want.
}
for(int j = 0; j < x_length_d2 && x_empty; j++) {
if(x[i][j] != 0) x_empty = 0;
}
}
The sizeof returns the size of short** (pointer to pointer to short) which appears to be 4 bytes in your system. If you allocate memory, you should know how many bytes have you allocated, and pass this value as well.
For example:
size_t size_allocated = 0;
short** y = functionThatReturnsAnArray(&size_allocated);
short ** functionThatReturnsAnArray(size_t * size) {
short ** buff;
size_t size_to_allocate = 5 * sizeof(short *);
buff = malloc(size_to_allocate);
if (!buff) {
*size = size_to_allocate;
}
else {
*size = 0;
}
return buff;
}
You cannot check if a variable has been assigned to. The value of an uninitialized variable is undefined IIRC. According to Assigning pointer to uninitialized variable changes it value? (found by Seth Carnegie), even accessing it causes undefined behaviour.
The solution? Explicitly assign a sentinel value and check for that. For pointers, NULL usually makes sense.

Resources