I'm getting confused while trying to make the tic tac toe game in c. I'm following a book that uses a single char array of 8 elements to create the board. I know an array[8] contains 9 elements, but if the array is declared as char array, since it has to contain spaces to make the empty board for the game, shouldn't it be array[9], since it has to contain the 9 characters plus a null character '\0'? I'm having the same doubt when converting the board to a 2d array, since I understand the board should be made with an array[3][3], but if I want to declare it as char, where is the place for the null character?
An array of characters can hold any value in any position. It's only when you want to use certain functions that you need to make sure that there's a NUL character (that's a 0, not a '0'!) at the end of the string - that tells the function when to stop processing!
So: char john[4] = { 'J', 'o', 'h', 'n' }; is perfectly legal - just don't pass john to strlen(), since it will keep counting until it finds a 0 value, and there aren't any in the array!
Also: char tictactoe[3][3]; doesn't need a 0 anywhere - unless you try to pass the whole array to printf() for some reason...
Note that you can safely do the following:
printf(" %c | %c | %c \n", tictactoe[0][0], tictactoe[0][1], tictactoe[0][2]);
printf("---+---+---\n");
printf(" %c | %c | %c \n", tictactoe[1][0], tictactoe[1][1], tictactoe[1][2]);
printf("---+---+---\n");
printf(" %c | %c | %c \n", tictactoe[2][0], tictactoe[2][1], tictactoe[2][2]);
because using %c means "print one character", not "print a string of characters".
The form of a string that ends in a NUL is often called an ASCIIZ (ASCII-Zeroed) string, and is the reason why a nine-char array can only hold an eight-character string (the opposite of what you said) - it needs the ninth to hold the NUL.
And, as always in C, any array goes from 0 to length-1, hence the [0], [1] and [2] in my example
The terminating zero is needed if a character array is used to store strings.
In the case of your task there is no need to store strings in the array.
So in C you may declare for example a 3*3 array the following way
char board[3][3] =
{
" ", // three spaces
" ",
" "
};
Each element of the array will not contain the terminating zero though it is initialized by a string literal.
On the other hand you can include the terminating zero in each element if you think that it will be simpler to output such an array. In this case the array should be defined like
char board[3][4] =
// ^^^
{
" ", // three spaces
" ",
" "
};
As for your statement that
an array[8] contains 9 elements
then the array is declared as having exactly eight elements. :)
I think you mean string literals. For example string literal "Hi" in C has type char[3] due to the terminating zero that is stored in the literal.
2D arrays are essentially 1D arrays with added ease of use for the programmer. The book you read probably just stores the values at cells, and displays them instead of a chunk of characters as string, like you said. This is a bit more efficient than storing the entire board as string.
Suppose you want to store a 2D array of 4x4 area. You can represent it as a 1D array of size 16, and access indicies like so:
arr[j + i * 4]
Where j is where you are in that 4 unit block, and i is what 4 unit block you are in.
Also, an array of size [8] has 8 elements. Ex:
char arr[8]; // has 8 elements, not 9
I know an array[8] contains 9 elements
No, why it should be? An array, defined like int arry[8] contains 8 elements only. That too, in C, array indexing is 0 based, means, for an array as above, only array[0] to array[7] will be valid access.
That said, for a char array, is to be used as string, should have the space for a null-terminator, too. So, if you want to have a char array of 9 elements and want to use it as a string, you need to define it as char[10].
Using a character as the value of an array has nothing to do with the fact that an array of char can decay to a pointer char* and be interpreted as a NUL terminated string.
A string doesn't have a specific type in C, it's just a way to interpret some data. So you are mixing two concepts.
A char array doesn't have to be NUL terminated, it requires NUL termination if you are going to use it with functions which will use the data as a string.
Having a char board[3][3] is perfectly legal and has room for 9 char elements, it doesn't require \0 since you are not going to use that data as a string.
Related
I have an abstract concept to use a for-loop to get specific adjacent characters of a string and add it to a stack, basically take all the constants of a string expression and add it to the stack separately; For example string: "1111+(2222-3333)" would be put in to the stack like "1111","2222", and "3333". I have a code below to start with that abstract concept but first trying it out with a simple one, and unfortunately it doesn't output the desired result of copying the specific adjacent characters.
char expression[20]={""},sub[20]={""};
scanf("%[^\n]%*c",&expression);
sub[15]=expression[15];
sub[16]=expression[16];
sub[17]=expression[17];
sub[18]=expression[18];
printf("%c %c %c %c\n",sub[15],sub[16],sub[17],sub[18]); //to check if copied successfully
printf("sub= %s",sub); //doesnt print expected output
After this declaration
char expression[20]={""},sub[20]={""};
all elements of the array sub contain zeroes.
You changed elements of the array starting from the position 15
sub[15]=expression[15];
sub[16]=expression[16];
sub[17]=expression[17];
sub[18]=expression[18];
The elements before the position still store zeroes.
So this call of printf
printf("sub= %s",sub);
assumes that the array contains an empty string because it first character is the terminating zero character '\0'.
Instead you could write
printf("sub= %s",sub + 15 );
Or you could change the assignments like
sub[0]=expression[15];
sub[1]=expression[16];
sub[2]=expression[17];
sub[3]=expression[18];
and then use
printf("sub= %s",sub);
Pay attention to that the second argument of this call of scanf
scanf("%[^\n]%*c",&expression);
is incorrect. You have to write
scanf("%[^\n]%*c",expression);
I'm working on a homework that has to do with strings.
Here's the code
int main(){
char a[50][50];
int n;
printf("Enter the value of n\n");
scanf("%d",&n);
printf("Enter %d names\n",n);
fflush(stdin);
for(int i=0; i<n; i++){
gets(a[i]);
}
I tried to change the char a[50][50] into char a[50] but the entire program didn't run, came along with this error message: "Invalid conversion from 'char' to '*char'
I don't really understand how this works.
char a[50][50] declares a to be an array of 50 arrays of 50 char.
Then a[0] is an array of 50 char, and so is a[1],a[2]. a[3], and so on up to a[49]. There are 50 separate arrays, and each of them has 50 char.
Since a[0] is an array of 50 char, a[0][0] is a char. In general, a[i][j] is character j of array i.
gets(a[i]) says to read characters from input and put them into a[i]. For this to work, a[i] must be an array of char—gets reads multiple characters and puts them in the array. If a[i] were a single character, gets could not work.
Although gets(a[i]) says to put characters into a[i], it works by passing an address instead of passing the array. When an array is used in an expression other than as the operand of sizeof or the address operator &, C automatically converts it to a pointer to its first element. Since a[i] is an array, it is automatically converted to a pointer to its first element (a pointer to a[i][0]). gets receives this pointer and uses it to fill in characters that it reads from the standard input stream.
char a[50][50] declares a as a 50-element array of 50-element arrays of char. That means each a[i] is a 50-element array of char. It will be laid out in memory like:
+---+
a: | | a[0][0]
+---+
| | a[0][1]
+---+
| | a[0][2]
+---+
...
+---+
| | a[0][49]
+---+
| | a[1][0]
+---+
| | a[1][1]
+---+
...
+---+
| | a[1][49]
+---+
| | a[2][0]
+---+
...
This code is storing up to 50 strings, each up to 49 characters long, in a (IOW, each a[i] can store a 49-character string). In C, a string is a sequence of character values including a 0-valued terminator. For example, the string "hello", is represented as the sequence {'h', 'e', 'l', 'l', 'o', 0}. That trailing 0 marks the end of the string. String handling functions and output functions like puts and printf with the %s specifier need that 0 terminator in order to process the string correctly.
Strings are stored in arrays of character type, either char (for ASCII, UTF-8, or EBCDIC character sets) or wchar_t for "wide" strings (character sets that require more than 8 or so bits to encode). An N-character string requires an array that's at least N+1 elements wide to account for the 0 terminator.
Unless it is the operand of the sizeof or unary & operator, or is a string literal used to initialize an array of character type, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression will be the address of the first element of the array.
When you call
gets( a[i] );
the expression a[i] is converted from type "50-element array of char" to "pointer to char", and the value of the expression is the address of the first element of the array (&a[i][0])1. gets will read characters from standard input and store them to the array starting at that address. Note that gets is no longer part of the standard C library - it was removed in the 2011 version of the standard because it is unsafe. C does not require any sort of bounds checking on array accesses - if you type in more characters than the target buffer is sized to hold (in this case, 50), those extra characters will be written to memory immediately following the last element of the array, which can cause all sorts of mayhem. Buffer overflows are a popular malware exploit. You should replace the gets call with
fgets( a[i], 50, stdin );
which will read up to 49 characters into a[i] from standard input. Note that any excess characters are left in the input stream.
Also, the behavior of fflush is not defined for input streams2 - there's no good, safe, portable way to clear excess input except to read it using getchar or fgetc.
This is why you got the error message you did when you changed a from char [50][50] to char [50] - in that case, a[i] has type char, not char *, and the value of a[i] is not an address.
Microsoft's Visual Studio C compiler is a notable exception - it will clear excess input from the input stream. However, that's specific to MSVC, and not portable across different compilers. The operation is also a little nonsensical with respect to "flush" semantics.
Basically, in C this signifies an array of length 0 to 50 of that contains the character value of 50 in each cell of the array
That program seems to store n names in the array a. It first asks for the number of names, and then the names. The method char *gets(char *str) stores each different line in an entry of a.
n has 2 dimensions. The first refers to the number of names, and the second is for the length of each name. Something like n[number_of_names][lenght_of_name]
However, it will probably crash if the user provides an n > 50, or if a name contains more than 50 chars.
Also, gets() is dangerous. See this other post.
EDIT: Changing a to one dimensions makes the program try to store a whole line inside a char, hence the error
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 6 years ago.
Improve this question
I tried to populate an array of structs defined as follows:
typedef struct{
char directive[5];
}directive_nfo_t;
By using the following:
directive_nfo_t directive_list[]=
{
{"ALIGN"},{"ASCII"},{"BSS"},{"BYTE"},{"END"},{"EQU"},{"ORG"}
};
To my surprise, the first few elements were corrupted like so:
[0]= ALIGNASCIIBSS
[1]= ASCIIBSS
[2]= BSS
...
Until I made the following change:
typedef struct{
char directive[6]; <-- made char array +1
}directive_nfo_t;
Then the first few arrays were correct like so:
[0]= ALIGN
[1]= ASCII
[2]= BSS
...
My question is what happens in the background to explain this behavior?
Regards.
In C, a string is a sequence of character values followed by a 0-valued terminator; the string "ASCII" is represented by the character sequence 'A', 'S', 'C', 'I', 'I', 0. Thus, you need a six-element array to store the string.
For a string that's N characters long, you need an array of N+1 characters to store it.
When you explicitly initialize a char array as string literal in the way you do:
char some_array[] = {"ALIGN"};
the compiler actually populates the 0th to 4th "position" (total of 5 positions) with the characters inside quotation marks, but also the fifth position with \0 without requiring you do it explicitly (if it has space enough). So the size equals 6. You exceed the boundaries if you don't count the \0 character into the size calculation and restrict the size to 5. Compiler would omit the terminating character.
In your case it looks as if the first element of the next member "overwrote" what should have been the omitted \0 character of the previous, since you haven't reserved a place for it. In fact the "mechanics of populating the array" boils down to the compiler writing as much data as could fit inside the boundaries. The address of the first position of the next member string logically corresponds to your assignment, although the \0 from the previous is missing.
Since your printf() format tag was %s, the function printed the characters until it reached the first \0 character, which is in fact undefined behavior.
That's why
char directive[6];
was correct size assignment in your code.
If the char array is big enough, C compiler automatically places a '\0' after the text.
If it is just large enough for the text, that terminator is omitted, which is what has happened here.
If there isn't even room for the text, the compiler will say something like "too many initialisers" or "array bounds overflow".
The struct array elements are adjacent in memory. The first two items lack a terminator, so the second item printed only stops at the terminator after the third item. The first item, is also printed until it reaches that same terminator. By making the array size 6, the compiler was able to place a terminator after every item.
Unlike in C++, C allows you to (unintentionally) shoot yourself in the feet, by allowing to omit NUL terminating character '\0' in the char array initializer when there is no room for it. Your case can be narrowed down to a simple array definition such as:
char str[5] = "ALFAP";
which is a syntatic shortcut to:
char str[5] = {'A', 'L', 'F', 'A', 'P'};
It may be kind of misleading, because in different context the same "ALFAP" represets string literal, that always has the ending NUL character:
char* str = "ALFAP" // here, "ALFAP" always contains NUL character at the end
My question is what happens in the background to explain this behavior? Regards.
You have an array of struct directive_nfo_t type and each struct directive_nfo_t holds array of five characters (in your first example).
The output that you were getting when you have 5 character array in directive_nfo_t type was basically due to two things-
Array elements are stored in consecutive memory locations.
In C, the abstract idea of a string is implemented with just null terminated array of characters.
When you have declared an array of directive_nfo_t type, each element of directive_nfo_t is stored in consecutive memory location and each element has 5 character array(which are also stored in consecutive locations) in it. And in your Initialization list({"ALIGN"},{"ASCII"},{"BSS"},{"BYTE"},{"END"},{"EQU"},{"ORG"}) for the array, you have used all the 5 characters in storing your data in first two elements of directive_nfo_t ("ALIGN" and "ASCII"). As, in C, functions which operate on character array to implement abstract idea of string, assume that a string will be terminated by using a null character at the end. Therefore, in the first two elements of directive_nfo_t array, the printf will keep on printing characters until it reaches null character(which it will find in element storing character array "BSS"). After printing ALIGN, printf will access the first character of second element of the array of directive_nfo_t (character A of ASCII). It occurred because there was not space for null character in the first element of array of directive_nfo_t type and compiler wouldn't add characters beyond array size as it does array bound check. From the third element of you array, you have enough space for null character and hence, printf works as expected.
You will get UNDEFINED BEHAVIOR if you allocate less memory to store your character array and use those functions which assume null terminated character array. Always set the size of the character array to MAX + 1 when you want to store maximum MAX characters in your array.
So I want to know how to store an actual character into an array.
char arr[4] = "sup!";
char backwards[4];
backwards[0] = *(arr + 3);
I guess my second question is if I do this, will, if i prompt a printf of backwards[0] using %c, will the actual character appear?
First off, let's fix your array size problem:
Character arrays in C are null-terminated: This means that you need to add space for a trailing \0 to terminate your string. You could use char arr[5] on the first line. (Note that if you are ABSOLUTELY CERTAIN you are NEVER going to use this array of characters with any of the C string handling functions, AND you assigned your characters individual as chars instead of as a string, this is not technically required. But save yourself some debugging time and use up the extra byte.) This is probably the source of your "weird error."
It seems like you know, but the other thing to bear in mind is in C, arrays are zero-based. This means that when you declare and array like char arr[4], you really get
arr[0]
arr[1]
arr[2]
arr[3]
C has no qualms about letting you walk off the end of your array and stomp on data or read in bad values. Here be dragons. Be careful.
Now, on to your actual questions:
1) You assign actual characters using single quotes arr[2]='x'; If you use double quotes, you are assigning a C string, which is null-terminated, as discussed.
2) Yes, printf with %c should do the trick.
Let's say you have:
char[5] = "March";
this won't work in C although:
char[0]='M'
char[1]='a'
char[2]='r'
char[3]='c'
char[4]='h'
char[5]='\0'
For some reason, I have to say to C that char[6]="March" and not char [5].
Why is this? What goes into char[6]?
First things first, char is not a valid variable in C, it's a keyword. You probably meant
char xyzzy[6];
or something similar, which would create a character array called xyzzy. But, once that's fixed up, nothing goes into xyyzy[6]. The statement char xyzzy[6]; means an array of six characters, the indexes of which are 0 through 5 inclusive: {0,1,2,3,4,5}, that's six elements.
In any case, unless you need the array to be bigger, you're usually better off letting the compiler choose the size with:
char xyzzy[] = "March";
A string literal, "March" in this case, has an implicit null terminator so a char[] array requires 6 elements to store it. To quote the relevant points from the section 6.4.5 String literals of the C99 standard:
A character string literal is a sequence of zero or more multibyte characters enclosed in
double-quotes, as in "xyz".
In translation phase 7, a byte or code of value zero is appended to each multibyte
character sequence that results from a string literal or literals.
In both cases the code is overrunning the end of the array. The code currently has undefined behaviour.
Change to:
char a[6] = "March";
The second code snippet accesses beyond the end of the array as indexes run from 0 to N - 1, where N is the number of elements in the array. For an array char a[5]; the valid index are 0, 1, 2, 3, 4.
The null terminator \0 goes in the last slot.
It is there because otherwise there would be no way to check the length of the string.
There are 6 elements if you count from 0 to 5 included.
So you must declare a char[6] in order to have str[0] to str[5].
char [5] means, you have memory for 5x sizeof(char). 0-5 are six times sizeof(char): 0 first, 1 second, 2 third, 3 fourth, 4 fifth, 5 sixth. So you need a segment with 6 times sizeof(char): char [6]. The first cell, zero, consumes space, too.
Nothing goes into char[6], but you still need a char[] of size 6 to hold the 6 characters including the null-terminator byte. They will go into char[0] through char[5]. char[6] remains undefined.
char array[n]
means an n elements long array, not an array whose last index is n. Because in C, arrays are zero-based, it means that the last valid index of an n-element array is n - 1. Since there's a zero terminator for a string, and "March" is 5 letters, that's a total of 6 characters, so you have to write char str[6] = "March";. If that's confusing for now, don't include the length of the array; for initialized arrays, the compiler will automagically fill it in, so you can write char str[] = "March"; instead.
Char is a keyword not a variable name, so don't use it as one.
Array indexing: that is counting the number of characters in an array begining from 0, i.e a[0].
Suppose there are 5 characters in the array (for eg: tiger) then a[0] = 't' and a[4] = 'r' and all the string literals in this case an array of characters ends in a '\0' i.e a EOF
character. So to store an array of n characters use a[n] compiler will add '\0' at the end of that array.