Why is the array not accepting a null terminator? - c

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

Related

C : Lvalue required error when assigning to string

I made a simple structure with both integer and char types, I am facing an Lvalue required error when assigning "Structures" to my LE structure string. I don't understand why because that's normally how I would assign a string.
#include<stdio>
#include<conio>
struct Lesson{
int lessonNumber;
char lessonName[80];
}LE;
main(){
LE.lessonName = "Structures";
LE.lessonNumber = 1;
printf("%s",LE.lessonName);
printf("%d",LE.lessonNumber);
getch();
}
One easy way to go about is (If you don't want to call strcpy):
#include<stdio.h>
struct Lesson{
int lessonNumber;
char *lessonName;
}LE;
int main(void){
LE.lessonName = "Structures";
LE.lessonNumber = 1;
printf("%s",LE.lessonName);
printf("%d",LE.lessonNumber);
}
Here lessonName is a pointer and not an array. With the assignment operator here: LE.lessonName = "Structures", you are assigning the address of where the string "Structures" is stored to LE.lessonName.
i don't understand why. because thats normally how i would assign a
string
There are a couple of things to keep in mind here. If you declare lessonName as an array (as you have done), you should keep in mind that an array is not something you can assign to. What you can assign to is a specific place / index in an array using the = operator. Thus you could build your c-string character-by-character or, you could call the strcpy function to copy a string character-by-character (including the \0) to lessonName.
When you use a pointer (char *lessonName) and say something like LE.lessonName = "Structure", this piece of string can't be modified. You can't do LE.lessonName[0] = 'g'. Of course you could modify LE.lessonName to point to some other string later on like LE.lessonName = "cat";.

what is the value of an empty cell of a 2d array?

i am kind of new in c and i am trying to figure things out.
my question is, what i need to have in the place of '/0' , in order for it to skip
the "empty" cells?
i know i could do it the easy way and just have have all the .anoxi values in the condition, but i was just curious.
i have tried putting "", which gives me all the names (doesn't skip any of them) , '' which gives me "[Error] empty character constant" and
null, which gives me "[Error] 'null' was not declared in this scope"
struct t {
char anoxi[10];
char name[10];
char gramma [2];
}
int main() {
struct t array[5][12];
int r;
strcpy(array[4][1].anoxi, "+-1%");
strcpy(array[4][2].anoxi, "+-2%");
strcpy(array[4][5].anoxi, "+-0.5%");
strcpy(array[4][6].anoxi, "+-0.25%");
strcpy(array[4][7].anoxi, "+-1%");
strcpy(array[4][8].anoxi, "+-0.05%");
strcpy(array[0][0].gramma, "M");
strcpy(array[0][1].gramma, "K");
strcpy(array[0][2].gramma, "N");
strcpy(array[0][3].gramma, "O");
strcpy(array[0][4].gramma, "I");
strcpy(array[0][5].gramma, "R");
strcpy(array[0][6].gramma, "L");
strcpy(array[0][7].gramma, "V");
strcpy(array[0][8].gramma, "G");
strcpy(array[0][9].gramma, "A");
strcpy(array[0][10].gramma, "X");
strcpy(array[0][11].gramma, "S");
strcpy(array[1][0].name, "Black");
strcpy(array[1][1].name, "Brown");
strcpy(array[1][2].name, "Red");
strcpy(array[1][3].name, "Orange");
strcpy(array[1][4].name, "Yellow");
strcpy(array[1][5].name, "Green");
strcpy(array[1][6].name, "Blue");
strcpy(array[1][7].name, "Purple");
strcpy(array[1][8].name, "Grey");
strcpy(array[1][9].name, "White");
strcpy(array[1][10].name, "Gold");
strcpy(array[1][11].name, "Silver");
for (r=0; r<12; r++) {
if (array[4][r].anoxi!= '\0') {
printf("%s = %s\n",array[0][r].gramma, array[1][r].name);
}
}
return(0);
}
C has no concept of "empty". Variables in C represent actual physical memory locations, and they contain whatever that memory contains, which is either what they were initialized to contain, or some random value if they were never initialized (note that statics are initialized by default).
This doesn't prevent you from choosing to interpret one of the possible values of a variable as "empty", but that would be your choice, and entirely up to you. You would then have to initialize your variable/array with that value and check for it. Character variables often use the value '\0' for this, which should work for you--just make sure you take care of the difference between single characters and arrays: for example, ... if...gramma[0] == '\0'' ...
There is what you might consider an exception to this: one of the values pointer variables are allowed to take is a value called NULL, which is guaranteed not to point to anything. This is often used to initialize pointer variables but you still have to do the initialization and checking yourself.
Now that you got, it you may want to read my Structs (C), which offers a compact example, that might come in handy*.
First of all, allow me to question the validity of this code. Consider this equivalent example I made:
#include <stdio.h>
struct t {
char anoxi[10];
char name[10];
char gramma [2];
};
int main(void) {
struct t my_array[5][1];
if(my_array[0][0].anoxi != '\0')
printf("%s\n", my_array[0][0].anoxi);
return 0;
}
It will print, in my machine:
gsamaras#gsamaras-A15:~$ gcc -Wall px.c
gsamaras#gsamaras-A15:~$ ./a.out
����
Why?
Because, the memory the array holds is not initialized to anything, so its value is undefined, which invokes UNDEFINED BEHAVIOR!
We could fix this, by initializing every string, like this:
struct t my_array[5][1];
my_array[0][0].anoxi[0] = '\0';
if(my_array[0][0].anoxi[0] != '\0')
printf("edw %s\n", my_array[0][0].anoxi);
Or, as Mike suggested, you could use memset(), like this:
memset (my_array, 0, sizeof (my_array);
Usually we set the value of a variable to a predefined value, which for us, humans tells that this cell/string/whatever is empty.
c does not know that, unless we tell our program to keep an eye out of empty "things". We have to inform our program what is an empty "thing", especially how to identify it!
Here, you have a string and you check array[4][r].anoxi!= '\0', which is always true because the left-hand side is an array, which decays to pointer in this expression, as M.M said.
*I am not writing it here, since the answer is already too long
First of all, initialize the array to blank:
struct t array[5][12] = { 0 };
This means that any members you have not yet assigned contents to will have value 0 (converted to the type of that member). This is so that later on you can see if the member has been assigned something else by checking to see if it is still 0 or not.
Then you can check:
if ( array[4][r].anoxi[0] ) {
// ^^^^
Note that you must check anoxi[0] which is a char object. Checking anoxi, which is an array object, merely checks that the array exists in memory (which it tautologically does), not whether the contents of the array are some particular value.
NB. The != '\0' is redundant, I think it is clearer to omit it but you could use it if you want.

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

C: passing arrays to another method properly

/*
* PURPOSE
* Search if a string contains a string and print it out from there
*/
#include <stdio.h>
void searchHaystack(char cHaystack[], char cNeedle[]);
void showResult(int iOffset, char cHaystack[]);
int main() {
// Declarations
char cHaystack[50], cNeedle[50];
// Input
puts("Haystack:");
gets(cHaystack);
puts("Needle:");
gets(cNeedle);
// Call searcher
searchHaystack(cHaystack, cNeedle);
return 0;
}
void searchHaystack(char cHaystack[], char cNeedle[]) {
// Declarations
int iCntr, iCntr2, iFoundOffset;
// Search the haystack for the first letter of the needle
for (iCntr == 0; iCntr < 50 && cHaystack[iCntr] != '\0'; iCntr++) {
if (cHaystack[iCntr] == cNeedle[0]) {
iFoundOffset = iCntr;
for (iCntr2 == 1; iCntr2 < 50 && (cHaystack[iCntr+iCntr2] == cNeedle[iCntr2] || cNeedle[iCntr2] == '\0'); iCntr2++) {
if (cNeedle[iCntr2] == '\0') {
showResult(iFoundOffset, cHaystack);
}
}
}
}
}
void showResult(int iOffset, char cHaystack[]) {
int iCntr;
// Print the substring char by char
for (iCntr == iOffset; iCntr < 50 && cHaystack[iCntr] != '\0'; iCntr++) {
printf("%c", cHaystack[iCntr]);
}
printf("\n");
}
Looking at my debugger I noticed that cHaystack[] and cNeedle[] aren't passed to searchHaystack properly as only the first char is conserved. How do I fix this? I haven't learned about pointers yet.
Also, I'm getting this warning on all three for loops:
statement with no effect
What's up with that?
Actually, the entire array IS being passed, the debugger only shows the first char by default because in C, the system does not know the size of an array. It is something the program has to keep track of. Since you are using strings though, which are typically null terminated, try setting the watch variable "(char*)cHaystack" (without quotes) and see what the debugger shows then.
Also, assignment statements should have one = sign, not the double == sign. So:
for (iCntr = 0; ...
Should be used, NOT:
for (iCntr == 0; ...
Same with the other for loops.
You're starting the loop with iCntr == 0
This is a comparison, so it does not set iCntr to zero.
Use iCntr = 0 (a single equals sign)
The values are passed properly, but your expectation of how your debugger should display them is incorrect. As already mentioned, there is no string type in C. Instead, C uses char* variables -- pointers to characters; your char[] are equivalent to char*.
You know that the pointed-to character is the first character in a longer string, but the debugger doesn't. It displays the character that the pointer points to -- which you know to be the first of a longer string. The debugger, however, only knows it's a char*, and there must be a char to be pointed at, so it displays that char.
These are character arrays not strings. In C string are of type char * and you have to allocate the memory for them.
Of course when you say varname[5] that is the same as saying *(varname+5)
Basically you are going to have to learn about pointers to use strings in C.
EDIT
As pointed out below (and above by me) you can use character arrays like strings in C. HOWEVER, my point is that if you don't learn a little bit about pointers you are going to be in big trouble.
For example:
Not being able to view the string in the debugger.
Not putting a null as the last character in the array and having crazy random bugs
Forgetting that you only allocated X bytes for the array and going over the end
etc.
If you don't understand how pointers work in C, it is really hard -- if not impossible to work with the language.
I expect the prof will cover it next week.
Arrays are not first-class objects in C; when you pass an array as a function parameter, the type of the array expression is implicitly converted from "N-element array of T" to "pointer to T", and its value is set to point to the first element in the array[1].
In the context of a function parameter declaration, int a[] is the same as int *a (but this is true only in the context of a function parameter declaration); your searchHaystack function receives two pointers to char, which correspond to the first elements of the respective arrays. The debugger doesn't show you the whole array, because in the context of the function they are not arrays.
Also, NEVER, NEVER, NEVER USEgets(). Ever. It will introduce a point of failure in your code. Use fgets() instead. C does no bounds checking on arrays. If you call gets() for a buffer sized to hold 10 characters, and the user types in 100 characters, gets() will happily store those extra 90 characters in the memory following your buffer, potentially clobbering something important and leading to a crash or worse (buffer overruns are a common exploit for malware; the Morris worm exploited a call to gets() in sendmail).
The warning is coming from you using == instead of = to assign your loop counters.
The exceptions to this rule are when the array expression is an operand of either the sizeof or address-of (&) operators, or when the array is a string literal being used to initialize another array in a declaration.
The warning is probably caused by
iCntr == 0,iCntr2 == 1, iCntr == iOffset
I guess you were going, in fact, for:
iCntr = 0,iCntr2 = 1, iCntr = iOffset
As for passing the arrays, you could do something like ( using pointers ):
void searchHaystack(char* cHaystack, int cHaystackSize, char* cNeedle, int cNeedleSize )
...
for (iCntr = 0; iCntr < cHaystackSize && cHaystack[iCntr] != '\0'; ++iCntr )

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