if statements in c with NULL - c

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.

Related

Trying to use Struct to make a String array and comparing it to a String

#include <stdio.h>
typedef struct Name {
char Name[10];
}Name;
A(Name a) {
Name NameList[16] = {"", "Holly", "Zia", "Brandon","Jerry","Tom","Katie","Klein","Sophie","Brian","Mary","Ben","Annie","Percy","Zoe","Zack"};
for (int i = 0; i <= 15; i++) {
if (a = NameList[i]) {
for (int k = i; k <= 15; k++) {
printf(NameList + k);
}
break;
}
else {
continue;
}
}
}
I'm getting problems with if (a = NameList[i]) this part.. compiler tells me that I need pointers, but I'm not sure where I have to put them.. help?
a = NameList[i] is an assignment, not comparison. In general you need to use == for comparison.
In C a string is an array of chars, zero terminated. In order to compare strings in C you need to use strcmp. Note that it returns 0 if the strings are equal.
a is not actually a string, but contains one. a.Name is a string. Same applies to NameList[i].
A struct should not contain a member with the same name as the struct itself (even if your compiler accepts it, it is error-prone). You should rename the member Name (e.g. to data).
Therefore after modifying the struct definition, you should change your if to:
if (strcmp(a.data, NameList[i].data) == 0)
First of all the statement if (a = NameList[i]) {bla..} does not do what you think it does. It first executes the command a = NameList[i] and then evaluates if (a != 0) in which case the commands inside the if statement will be executed.
That's a mistake everyone has made at some point ,even more experienced programmers might make this mistake from time to time.
Now I see you are trying to compare two strings ,in C we do this using the function strcmp(a ,b) .If strcmp returns 0 ,the two strings you gave it are equal.
Another mistake you made ,is that you are comparing two structs instead of their contents. You have to use if(!strcmp(a.Name ,NameList[i].Name)) instead.
So your main issue is that you are comparing structs not their contents.

Why is the array not accepting a null terminator?

I'm trying to insert a null terminator at the end of this array. How would I fix it?
int cool_array[10] = {0};
int i = 0;
while (i < 5) {
cool_array[i] = 5;
i++;
}
cool_array[i] = {'\0'} // this is where the problem is. I get an error.
Error:
error: expected expression
legal_cards[legal_counter] = {'\0'};
^
1 error generated.
Firstly, null terminator at the end of this(integer) array doesn't make any sense. if its char array then it should be null terminated.
cool_array[i] = '\0'; is not required as you already initialize cool_array initially as below
int cool_array[10] = {0}; /* here itself cool_array all elements initialized with zero */
Secondly, if cool_array is char array like char cool_array[10] then it should be
cool_array[i] = '\0'; /* make sure i value is within range i.e 0 to 9 as you declare cool_array[10] */
Instead of
cool_array[i] = {'\0'};
As #achai pointed out, we usually reserve the term "null terminator" for use in connection with char arrays containing string data. Nevertheless, there's nothing inherently wrong with using the value 0 as an end-of-data marker in arrays of other types, too, but such a convention is by no means universal.
You receive an error because the syntax of your terminator assignment is wrong. You are assigning to cool_array[i], which has type int. The right-hand side of the assignment must therefore be an expression of type int. That can be '\0' or (100% equivalent) just 0, but the curly braces ({}) have no place there.
cool_array[i] = 0;
You are perhaps confused about the similar-appearing code in the declaration of cool_array:
int cool_array[10] = {0};
Note well that that is a declaration, not an executable statement, and there is no assignment within. It contains an initializer for the array, but although that has similar form, both the syntax and semantics are different from an assignment. Specifically, it says to initialize the first element of the array (explicitly) to 0, and implicitly to initialize all other elements (to 0).

Why give a variable a null value when declaring it?

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++;
}
}

Changing undefined values of an array

lets think of a two dimensional array; which looks like this:
[1][2][3][4][undefined][undefined][undefined]
[5][6][7][8][undefined][undefined][undefined]
[9][0][1][2][undefined][undefined][undefined]
Can I change the undefined values with a for loop like this?
for (i=0;i<7;i++)
{ for (j=0;j<3;j++)
{
if (Arr[i][j]=="the value of undefined, which I wonder")
Arr[i][j]=0;
}
}
I remember using NULL keyword on C#, but that obviously doesnt work for C.
Thank you for your help!
Note: I dont need any other methods than that to solve the problem, just wondering if there is a keyword or phrase to help me solve it that way.
If the elements of the array are a floating-point type, you can use a NaN to indicate that they are not set to a number (in most C implementations; this is not in all C implementations but is common). You would have to initialize the array to contain NaNs; they will (generally) not be placed there by default.
If the elements of the array have another type, you would have to select a value to designate that the element has not been otherwise assigned yet, and that could create problems using the array normally.
After you #include <math.h>, you can test whether a C implementation supports NaNs with:
#if defined NAN
// NaNs are supported.
#else
#error "This program requires support for NaNs."
#endif
You can test whether an object x is a NaN with:
if (isnan(x)) …
You can set an object to a NaN with:
x = NAN;
In addition to Eric's answer, there are several other ways to handle this sort of situation in C, with varying amounts of extra baggage and mental grief. That is: these are ways to to express a value which represents undefined or unset values in your domain. We are not talking about the actual indeterminate values you will generally get back from your C implementation if you allocate an array without initializing it and then access it.
Method 1: NaN (not-a-number) values, as indicated in Eric's solution. Works in the specific case where you are manipulating floats, and there is no possibility that NaN is going to be used as a legitimate defined value in your domain. If you were storing characters, the null character '\0' might also be a reasonable choice for undefined.
Method 2: Pointers. C does have NULL, just like C#. However, it only applies if you're manipulating values of pointer types. So, instead of:
int a[3];
a[0] = 1;
a[1] = 2;
a[2] = 0; /* blech -- I really want this to mean 'undefined',
but what if I really needed 0 as a numeric value
in my array? In that case, this doesn't work! */
I could do this:
#include <stdlib.h>
int* integer_new(int i) {
int* result = (int*) malloc(sizeof(int));
*result = i;
return result;
}
int* a[3];
a[0] = integer_new(1);
a[1] = integer_new(2);
a[2] = NULL;
and now you have a value which can easily be tested and distinguished from your normal integer values. This is in theory what's going on behind the scenes in the C# code, I believe. But you can see the disadvantages pretty quickly: you have a bunch of heap-allocated objects now where you didn't before, and you now have to manage them, freeing them as appropriate when you're done with them.
There's a refinement of this if you're dealing with something like the flyweight pattern where these values are stack-allocated or pre-allocated elsewhere. In that case, you could just take the addresses of those values, stick them in the array, and not have to heap-allocate them yourself. But you still have to contend with an extra layer of indirection.
Method 3: The maybe pattern (which I'm stealing from Haskell). Something like this:
typedef struct maybe_int_ {
int has_value; /* 1 if yes, 0 if no */
int value;
} maybe_int;
maybe_int maybe_nothing(void) {
maybe_int result;
result.has_value = 0;
return result;
}
maybe_int maybe_just(int i) {
maybe_int result;
result.has_value = 1;
result.value = i;
return result;
}
maybe_int a[3];
a[0] = maybe_just(1);
a[1] = maybe_just(2);
a[2] = maybe_nothing();
This works better with the stack, so it's generally an improvement over pointers in that way, but you still have a lot more to deal with for bookkeeping.
Method 4: Unions. Similar to Method 3, but you might do something like this if you can have multiple kinds of values in your array:
typedef enum {
BOXED_TYPE_UNDEFINED,
BOXED_TYPE_INT,
BOXED_TYPE_FLOAT
} boxed_type;
typedef struct boxed_ {
boxed_type type;
union {
int int_value;
float float_value;
} u;
} boxed;
boxed boxed_undefined(void) {
boxed result;
result.type = BOXED_TYPE_UNDEFINED;
return result;
}
boxed boxed_int(int i) {
boxed result;
result.type = BOXED_TYPE_INT;
result.u.int_value = i;
return result;
}
boxed boxed_float(float f) {
boxed result;
result.type = BOXED_TYPE_FLOAT;
result.u.float_value = f;
return result;
}
boxed a[3];
a[0] = boxed_int(1);
a[1] = boxed_float(2.0f);
a[2] = boxed_undefined();
If you're already using a union plus a type discriminator, then this solution might be particularly easy to implement.
What do all these solutions have in common? The idea of a sentinel value: some value you're storing in your array which is guaranteed to not be used for anything else in your domain, so you're free to interpret it to mean an undefined value. As you can see, there are a lot of ways to inject sentinel values into your domain.
Here's one solution that doesn't involve sentinel values. Method 5: go outside the box.
int a[3];
unsigned char adef[3];
a[0] = 1; adef[0] = 1;
a[1] = 2; adef[1] = 1;
adef[2] = 0; /* I would set a[2] = 0 here as well
because I dislike uninitialized
array values! */
If you really can't muck with the values in your domain in any way that would allow you to define a sentinel value, then just store the extra "definedness" of values somewhere else. I've never had to resort to this myself, but I have found that the general technique of a separate table of related data does come in handy from time to time.
Let me say , there is no value means:"the value of undefined, which I wonder" , if you didn't initialized it , it is unkown value.
Arrays in C have undefined value if you do not initialize them to a value; That means it can be 0 0 0 0 0 900000 0 0 0 0 0 etc.
Yes there is a undefined value but as per the name it's well ...undefined - as in there is no set value.
You can just overwrite them like you are doing. . Even better though would be to use memset
The reason it's undefined is you're just getting a chunk of memory - anything could be sitting (value wise) in that memory.
edit: ok unless you static init the array of course.

In C: How to set a pointer to a structure member that is an array?

How should I write my code to example a specific array index of an array that happens to be a member of a structure? The following code is giving me problems.
// main.c
void clean_buffers(void); // prototype
struct DEV_STATUS {
unsigned char ADDR;
unsigned char DEV_HAS_DATA;
unsigned char ETH_HAS_DATA;
unsigned char DATA[20];
};
struct DEV_STATUS g_cmdQueue[60] = {0};
void main(void) {
clean_buffers();
while (1) {
;// MCU tasks
}
}
void clean_buffers(void) {
unsigned char theCount = 0;
byte queIdx;
for (queIdx = 0; queIdx < 59; queIdx++) {
struct DEV_STATUS *p_struct;
unsigned char *p_data;
p_struct = &g_cmdQueue[queIdx];
p_data = &p_struct->DATA;
p_struct->ADDR = 0;
p_struct->DEV_HAS_DATA = 0;
p_struct->ETH_HAS_DATA = 0;
theCount = 0;
while(*(p_data+theCount) != 0) {
*(p_data+(theCount++)) = 0;
}
}
} // EOF main.c
I get a compiler error "struct/union member expected" on the following line:
p_data = &p_struct->DATA;
How should I write a pointer if I was to access, for example, the specific value of structure member DATA[3]? I'm confused, I thought that as p_data = &p_struct->DATA; is defined, I should be able to get it by using *(pdata+3) but I guess I'm missing something.
Are you sure you are compiling the same code you posted here?
If your compiler complains at this line
p_data = &p_struct->DATA;
with a "struct/union member expected" message, your compiler is probably broken.
Note, that &p_struct->DATA is a perfectly valid expression in C. There's absolutely no problems with this expression by itself.
The problem here is just that this is not what you need in your case. &p_struct->DATA returns a pointer to the entire array 'DATA', i.e a pointer of type unsigned char (*)[20]. You are trying to assign this value to a pointer of type unsigned char *. This is illegal in C, since the types are completely different, but traditionally C compilers responded to it with a mere "type mismatch" warning and performed an implicit conversion (which, BTW, means that your original code, albeit "dirty", should still work as intended).
Even if some compiler decides to flag this mismatch as an error (which is fine), it still should not complain about any problems of "struct/union member expected" kind. There's no such problems here.
P.S. As other already said, what you really need is p_data = &p_struct->DATA[0], but that still does not explain your compiler's strange behavior. Could it be that 'DATA' is a macro defined somewhere before the 'clean_buffers' definition?
Added 10/19/2009: Nate, in your code you access your array using an index theCount. Since you are using the index access anyway, there's really no reason to even create the pointer you are trying to create. The code will work perfectly fine without any additional pointer, just acess the DATA field directly
theCount = 0;
while (p_struct->DATA[theCount] != 0) {
p_struct->DATA[theCount++] = 0;
(I'd probably use a for cycle here).
If you really insist on creating this pointer and still using the index access, the code should look something like the following (the others already suggested that more than once)
p_data = p_struct->DATA; /* or &p_struct->DATA[0] */
...
theCount = 0;
while (p_data[theCount] != 0) {
p_data[theCount++] = 0;
Moreover, you can opt for a more "exotic" variant :)
unsigned char (*p_data)[20]; /* <- note: declared differently */
...
p_data = &p_struct->DATA; /* <- note: your original version */
...
theCount = 0;
while ((*p_data)[theCount] != 0) {
(*p_data)[theCount++] = 0;
However, returning to a unsigned char *p_data version, since you create that pointer, it might make more sense to use a "sliding pointer" technique instead of using index access
unsigned char *p_data;
...
p_data = p_struct->DATA; /* or &p_struct->DATA[0] */
...
while (*p_data != 0) {
*p_data++ = 0;
As always, it is all a matter of personal preference. Of course, nothing of this will work until you get rid of that interference from the macro.
Lose the & in
p_data = &p_struct->DATA;
p_struct is already a pointer. Afterwards, use p_data[] to access your array.
What you should write is one of two things:
p_data = p_struct->DATA; // DATA is the address of the first element.
OR
p_data = &p_struct->DATA[0]; // taking the address of the first element.
Simply remove the & at the beginning, like this:
p_data = p_struct->DATA;
That is special sintax for arrays (remember they are passed always as reference) and it is equivalent to:
p_data = &p_struct->DATA[0];
And yes, now you can use *(pdata+3)
Hope it helps.
Oops! Thank you AndreyT
struct DEV_STATUS *p_struct;
unsigned char *p_data;
p_struct = &g_cmdQueue[queIdx];
p_data = &p_struct->DATA;
p_struct is a pointer to struct DEV_STATUS.
&p_struct is the address of a pointer to struct DEV_STATUS (or a pointer to a pointer to a struct DEV_STATUS).
You probably want to change that line to
p_data = p_struct->DATA;
Oh ... your clean_buffers() function does not "clean" the element g_cmdQueue[59].
And, because it is a global object, the array g_cmdQueue is initialized to all zeros even before the first statement of main() exceutes.

Resources