What does char a[50][50] mean in C? - c

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

Related

Why does printf function ignore the latter \0? [duplicate]

This question already has answers here:
What happens if I do printf("one\0two");?
(4 answers)
How to print a string with embedded nulls so that "(null)" is substituted for '\0'
(4 answers)
Closed 3 years ago.
I am stuck with some features that \0 has.
I know that \0 is a null character and it is a term to indicate that the formal is a string.
int j;
j = printf("abcdef\0abcdefg\0");
printf("%d", j);
return 0;
When I tried to print "abcdef\0abcdefg\0" out, C would only print string 'abcdef' and '6' instead of both 'abcdef' and 'abcdefg' which would sum up to 13. Why does this happen?
"abcdef\0abcdefg\0", the string literal, is effectively a static, const (for all intents an purposes) char array and so it has an associated size that the compiler maintains:
#include <stdio.h>
#define S "abcdef\0abcdefg\0"
//^string literals implicitly add a(nother) hidden \0 at the end
int main()
{
printf("%zu\n", sizeof(S)); //prints 16
}
But arrays are treated specially in C and passing them as a parameter to a function or almost any operator converts them to a pointer to their first element.
Pointers do not have an associated size.
When you pass a char const* to a function (e.g., printf), the function receives just one number--the address of the first element.
The way printf and most string functions in C obtain the size is by counting character until the first '\0'.
If you pass a pointer to the first element of a char array that has explicit embedded zeros in it, then for a function that counts until the first '\0', the string effectively ends at the first '\0'.
A string in C is a sequence of characters followed by a NUL character, which is '\0'. There is no separate "length" field.
When a string appears as a literal, such as "hello", what actually gets stored in memory is:
'h', 'e', 'l', 'l', 'o', '\0'
So you can see that if your string itself contains a '\0', as far as any of the C standard library functions are concerned, that's the end of the string.
Once printf see the first '\0' in your string, it stops printing and returns, because that's the end of the format string. printf has no way of knowing that there's another string after the '\0'. Maybe there is--or maybe there's just random other program data in memory after that point. It can't tell the difference.
If you want to actually print the '\0' characters, then you need to have some other way to track the "real" length of the string and use a function that accepts that length as a parameter. Alternately you could add the '\0' characters during the formatting process by specifying %c in the format string and passing 0 as the character value.
Here
j = printf("abcdef\0abcdefg\0"); /* printf stops printing once \0 encounters hence it prints abcdef */
printf() starts printing from base address of string literal "abcdef\0abcdefg\0" i.e from a until first \0 char encounters. So it prints abcdef.
-----------------------------------------------------------------
| a | b | c | d | e | f | \0 | a | b | c | d | e | f | f | g | \0 |
-----------------------------------------------------------------
0x100 0x101 ...............| 0x100 - assume this as base address of the string literal
| |
starts printing when printf sees
from 0x100 memory first \0
location it stops the printing & returns.
And then printf() returns number of printable characters i.e 6.
printf("%d", j); /* prints 6 */
From the manual page of printf
RETURN VALUE
Upon successful return, these functions return the number of
characters printed (excluding the null byte used to end output
to
strings).

Simple single char array encryption needs an artificially long array to work?

Running a simple encryption on a single char array. It doesn't seem to work when the array size is less than or equal to 1, even though only a single char is changing.
The below works because yesCrypto[10] is set to 10 (or > 1).
char noCrypto[] = "H"; //sets an array to hold unencrypted H
char yesCrypto[10]; //sets array to hold encrypted H
yesCrypto[0]=noCrypto[0]+1;
//takes 'H' from noCrypto and turns it into an 'I' and moves it into yesCrypto.
printf("Encrypted string is '%s'\n", yesCrypto);
//prints Encrypted version of 'H', 'I'
The below does not work because yesCrypto[0] is set to 0, also does not work when set to 1.
char noCrypto[] = "H"; //sets an array to hold unencrypted H
char yesCrypto[1]; //sets array to hold encrypted H
yesCrypto[0]=noCrypto[0]+1;
//takes 'H' from noCrypto and turns it into an 'I' and moves it into yesCrypto.
printf("Encrypted string is '%s'\n", yesCrypto);
//prints 'IH'
Side question: why is it printing IH when it is not working probably.
Code is attempting to print a character array that is not a string using "%s".
yesCrypto[] is not certainly null character terminated.
char yesCrypto[10];
yesCrypto[0] = noCrypto[0]+1;
printf("Encrypted string is '%s'\n", yesCrypto); // bad
Instead, limit printing or append a null character.
// 1 is the maximum number of characters to print
printf("Encrypted string is '%.*s'\n", 1, yesCrypto);
// or
yesCrypto[1] = '\0';
printf("Encrypted string is '%s'\n", yesCrypto);
OP's 2nd code is just bad as object arrays of length 0 lack defined behavior.
// bad
char yesCrypto[0];
OP's edited post uses char yesCrypto[1];. In that case use
yesCrypto[0] = noCrypto[0]+1;
printf("Encrypted string is '%.*s'\n", 1, yesCrypto);
// or
printf("Encrypted character is '%c'\n", yesCrypto[0]);
Fundamentally, printing encrypted data as a string is a problem as the encrypted character array may contain a null character in numerous places and a string requires a null character and ends with the first one.
In the first case, you're supplying an array (as an argument to %s) which is not null-terminated.
Quoting C11, chapter §7.21.6.1,
s
If no l length modifier is present, the argument shall be a pointer to the initial
element of an array of character type.280) Characters from the array are
written up to (but not including) the terminating null character. If the
precision is specified, no more than that many bytes are written. If the
precision is not specified or is greater than the size of the array, the array shall
contain a null character.
In this case, yesCrypto being an automatic local array and left uninitialized, the contents are indeterminate, so there's no guarantee of a null being present in the array. So the usage causes undefined behavior.
What you're seeing in the second case is undefined behavior, too.
Quoting C11, chapter §6.7.6.2
In addition to optional type qualifiers and the keyword static, the [ and ] may delimit
an expression or *. If they delimit an expression (which specifies the size of an array), the
expression shall have an integer type. If the expression is a constant expression, it shall
have a value greater than zero. [...]
So, the later code (containing char yesCrypto[0];) has Constraints violations, it invokes UB.
A note on why this might not produce a compilation error:
gcc does have an extension which supports zer-length arrays, but the use case is very specific and since C99, the "flexible array member" is a standadized choice over this extension.
Finally, for
...also does not work when set to 1....
will lack the space for a null-terminator, raising the same issue as in the very first case. To put it in simple words, to make a char array behave like a string containing n elements, you need
size of the array to be n+1
index n to contain a null character ('\0').

Initialize 2d char array in c - tic tac toe game

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.

Confused why function isn't printing address

Could anyone explain why running the following code prints only the newline character?
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv) {
int x = 12;
char *s = (char *) &x;
printf("%s\n", s);
return 0;
}
Since we're casting &x as a string, shouldn't what is printed be the string representation of the address of x (presumably some hexadecimal memory address)?
A string is a sequence of characters, terminated by the special character '\0'. When you print a string using the "%s" format, the printf function takes the address as a base address and prints characters from that base until it finds the terminator. If the "string" isn't actually a string, you have undefined behavior.
If you want to print an address you should use the "%p" format:
printf("Address of variable x is %p\n", (void *) &p);
Your code exhibits undefined behavior because you are trying to print an int's address using %s.
%s in printf family of function is used to print \0 terminated character array or c-type strings
From C11 specs, 7.21.6.1 The fprintf function
(8) %s: If no l length modifier is present, the argument shall be a pointer to
the initial element of an array of character type.280) Characters from
the array are written up to (but not including) the terminating null
character. If the precision is specified, no more than that many bytes
are written. If the precision is not specified or is greater than the
size of the array, the array shall contain a null character.
280) No special provisions are made for multibyte characters
And later
(9) If a conversion specification is invalid, the behavior is
undefined.282) If any argument is not the correct type for the
corresponding conversion specification, the behavior is undefined.
282) See ‘‘future library directions’’ (7.31.11).
One of the many possibilities that may happen is: (I am assuming a lot about the implementation here)
your int appears in memory as following 4 bytes
s (not guaranteed to hold the same address)
s s+1 s+2 s+3 s+4
+---+---+---+---+
| 0 | 0 | 0 | 12|
+---+---+---+---+
&x
or
s (not guaranteed to hold the same address)
s   s+1 s+2 s+3 s+4
+---+---+---+---+
| 12| 0 | 0 | 0 |
+---+---+---+---+
&x
Where 12 or form-feed or \f is a non-printable ascii character and may not print anything on the screen.
When you reinterpret it as char * and print, an empty string is printed followed by the newline. Although this is not guaranteed and anything may happen from crashing to printing indefinitely (or even worse).
Correct way to print an int is:
printf("%d\n", x);

Confused about the Null Zero in C

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.

Resources