2D array of characters, printing extra character over limit? - c

The output of code
I want to create an array of character in which there are 'n' rows and each row have a character. In the given code I asked the user to enter the number of rows(n) then I create a variable 'chr' and each row contain only one character. Then I asked the characters one by one and store them in their respective rows but when I take the print of those characters something strange happens. The first row which should only store one character of its own stores all the characters of different rows. Why? can anyone explain to me this?
#include <stdio.h>
int main(void) {
int n;
scanf("%d", &n);
char chr[n][1];
for (int i = 0; i < n; i++) {
printf("Enter the %d character?\n", i);
scanf("%s", chr[i]);
}
// printing
for (int i = 0; i < n; i++) {
printf("\n%s\n", chr[i]);
}
return 0;
}

The first row which should only store one character of its own stores all the characters of different rows. Why? can anyone explain to me this?
scanf("%s", chr[i]);
%s reads a whole string until it encounters a white space character, such as newline \n, and writes it (excluding the white space character) into the first dimension; not only one character.
You also forgot that since you are trying to read a string a \0 is automatically appended to each string, but since the declaration of chr there is just place for one character in a dimension, not two.
A multi-dimensional array is allocated continously in memory, which provides the effect that the \0 character for the string in the previous dimension is stored at the first and only character of the next dimension; in the next iteration scanf overwrites then this \0 character to store the second character but again writes the \0 of this string into the first an only object of the following dimension and goes so on and on for each iteration, which ends up in a complete mess of Undefined Behavior, plus the \0 of the last string is written beyond the bounds of the complete multi-dimensional array.
So you can´t even say that they were stored in just one dimension, which isn´t the case, even if it seems like it would.
For more information about Undefined Behavior look at this question:
Undefined, unspecified and implementation-defined behavior
Rather use
scanf(" %c", &chr[i][0]);
with the %c format specifier to read only one character per iteration and implement a white space character before the %cformat specifier to catch the newline \n left in stdin by the scanf consumption of the previous loop walkthrough or any leading white space.
Also, change:
for(int i = 0; i<n; i++) {
printf("\n%s\n", chr[i]);
to
for(int i = 0; i<n; i++) {
printf("\n %c \n", chr[i][0]);
The whole code shall then be:
#include <stdio.h>
int main(void) {
int n;
scanf("%d", &n);
char chr[n][1];
for(int i = 0; i<n; i++) {
printf("Enter the %d character?\n", i);
scanf(" %c", &chr[i][0]);
}
// printing
for(int i = 0; i<n; i++) {
printf("\n %c \n", chr[i][0]);
}
return 0;
}

as to answer why its printing the other caracters, they are directly behind each other in memory, and as others pointed out since you told it to print a string, it treats those chars in a row as one string (which is an array of chars) until it encounters a termination char.
so in memory this
char array[3][1] = {{'a'},{'b'}{'c'}};
looks just like this:
char array[3] ={'a','b','c'};
or this
char array[3] = {"abc"};
the array variable is a pointer to the address in memory where the first char is positioned, if you use [] you just jump sizeof(char) amount of bytes to the next char,
with the 2D array this is similar, the 1st bracket makes you jump sizeof(2darray[0]) bytes, which is in this case the same as sizeof(char) since length is 1

Related

Why is the first value of my char array 10?

I'm new to programming but I wanted to make a program that gets as input a number, (length) and then stores a series of a's and b's of said length. Finally it should output the numbers as the ascii numbers. (so 97 and 98)
I thought I should malloc a char array of the size length and then do a for-loop over it and print everything as an integer.
The problem is however that I get a value 10 as the value of the first letter.
Thanks a lot for any help!
int main()
{
int length;
scanf("%d", &length);
char *matrix = malloc((length + 1 ) * sizeof(char));
for (int i = 0; i < length; i++)
{
scanf("%c", &matrix[i]);
}
for (int i = 0; i < length; i++)
{
printf("\n%d", matrix[i]);
}
return 0;
}
When inputting 3 on the first line and aba on the next line, I get 10 97 98.
However I expected it to be 97 98 97. Why do I get a value of 10 in the first place of the array?
Use
scanf(" %c", &matrix[i]);
^^^^
instead of
scanf("%c", &matrix[i]);
^^
When the format starts with a blank all white spaces are skipped.
From the C Standard (7.21.6.2 The fscanf function)
5 A directive composed of white-space character(s) is executed by
reading input up to the first non-white-space character (which remains
unread), or until no more characters can be read.
10 is the ASCII code of the (white space) new line character '\n' that was present in the input buffer after you entered the length of the array.
The first scanf() with the format string %d leaves a newline in the input buffer.
What happens here, is that your terminal collects input one full line at a time, passing it to the program, and then the scanf() only reads the digits from the buffer, leaving the newline character there for the next scanf() to see. The same would happen if you entered 10 abc: the space, abc and the newline would be left there.
This mismatch is not something people usually expect, and it's one of the things that makes scanf() annoying. I would suggest using fgets() instead to first read a full line, matching what the terminal gives, and then parse the number from it with sscanf() or strtol() (or atoi()).
This cleans up the issue at the point where the first line is read, instead of passing it on to the next input function to handle. Otherwise all your input functions are tied together, if the next input would be for a whole line with possible white space, you'd need to know if you expect to clear a pre-existing newline or not. (You could also replace the later scanf("%c") with getchar(), not that that matters with buffering though.)
That said, the scanf("%c")/getchar() loop may still see newlines if you enter lines that don't have as many characters as the loop expects, so if you don't want to see them at all, filter them out.
So, something like this:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int length;
char linebuf[100];
fgets(linebuf, 100, stdin);
length = strtol(linebuf, NULL, 10);
char *matrix = malloc(length + 1);
for (int i = 0; i < length; i++)
{
matrix[i] = getchar();
}
for (int i = 0; i < length; i++)
{
printf("\n%d", matrix[i]);
}
printf("\n");
return 0;
}
(The obvious downside of fgets() is that you have to decide on a maximum length for the input line, allocate a buffer and call another function in addition to it.)

The first char of my array doesnt get printed out

I want to program a Hangman game, but before comparing strings etc. I just wanted to scroll through the array automatically to see if that works - it doesn't, well, not as I imagined.
Everything besides the very first character gets printed out, but why?
int gameWon = 0;
char secretWord[7][1] = {{"H"},{"A"},{"N"},{"G"},{"M"},{"A"},{"N"}};
char guessedChar;
while(gameWon != 1)
{
printf("Guess a single letter: ");
scanf("%s", &guessedChar);
for(int i = 0; i < 7; i++)
{
printf("%c\n", secretWord[i][0]);
}
}
You're using the wrong format specifier to scanf:
scanf("%s", &guessedChar);
The %s format specifier expects a char * which points to the first element of a char array and places a null terminated string at that location. What you passed in was the address of a single char. This caused scanf to write past the memory location of guessedChar, invoking undefined behavior. In this case, it manifested as a nearby variable getting overwritted, specifically the first element of the array secretWord.
Change this to use %c instead, which is for reading single characters. Also, be sure to put a space before it in the format string to absorb any whitespace characters left in the input buffer:
scanf(" %c", &guessedChar);
The type that you specify in scanf is wrong, you pass in an address to a character but the format specifier %s expects a string which will cause undefined behavior. My guess is that it affects the rest of your code.
Also the type of secretword seems a bit odd, why not just an array or string?
char secretWord[] = "HANGMAN";
scanf is not a good choice of reading from the keyboard, instead use fgets() and strip off the ending \n or like in your case, just read the first char. Then you don't need to deal with the fact that scanf leaves characters in the keyboard buffer.
while (... )
{
printf("Guess a single letter: ");
char buffer[128];
if (fgets(buffer,sizeof(buffer),stdin) != NULL)
{
for (int i = 0; i < strlen(secretWord); ++i)
{
if (buffer[0] == secretWord[i])
{
...
}
}

C multidimensional array pointing problem?

Trying to take strings as input and place it in 2d array. Why is this given code showing different behavior. The last for loop "arr[i][j]" is not printing the string.It is not even printing a character also.
Why this code does not work.only this code.Not a new way to write it
This code takes input just fine(or at least the way needed.each row a single string no white space)And when a short string is stored remaining are filled with null after carriage return. When the arr[] is passed in last for loop everything seems fine only when arr[][] is passed ,the problem arises.But again arr[][] is initialized as arr[1][0] then arr[2][0] so should not it work!
#include <stdio.h>
#include <stdbool.h>
int main(void){
int i,j,m;
scanf("%d",&m);
char arr[m][50];
for(i=0;i<m;i++){
for(j=0;j<50;j++){
printf("please enter a string");
scanf("%s",&arr[i][j]);
/*j is always 0. arr[i] takes string without space and store ending with null*/
break;
}
}
//Everything fine upto this,including storing a small continuous string in arr[i](where i<50) and null terminating*/
for(i=0;i<m;i++){
for(j=0;j<50;j++){
printf("%s\n",arr[i][j]);
break;
}
}
}
You program has several issues, like using wrong format specifier:
scanf("%s",&arr[i][j]);
arr[i][j] is a character and you are using %s format specifier. If you want your program should take string as input, you just need to do:
scanf("%s",arr[i]);
Since, you have given the size 50 characters, put a restriction in scanf() to not to read more than 49 characters (the remain one character space is for null terminating character) like this:
scanf("%49s",arr[i]);
^^
Beware with this, it does not discard the remaining input from input stream when the input characters are more than 49 and the remaining characters will be consumed by consecutive scanf() call.
If you want to drop the extra input which wasn't consumed by scanf(), one way of doing it is to read and discard the extra input using a loop, like this:
int c;
while((c = getchar()) != '\n' && c != EOF)
/* discard the character */;
In case if you have any doubt on how this will discard the extra input, I would suggest first go through getchar().
Putting all these together, you can do:
#include <stdio.h>
int main(void){
int i,m;
scanf("%d",&m);
char arr[m][50];
for(i=0;i<m;i++){
printf("please enter a string");
scanf("%49s",arr[i]);
int c;
while((c = getchar()) != '\n' && c != EOF) // <=== This loop read the extra input characters and discard them
/* discard the character */;
}
for(i=0;i<m;i++){
printf("%s\n",arr[i]);
}
return 0;
}
EDIT
The below edit is because OP updated question and added - Why this code does not work.only this code.Not a new way to write it
Above in my answer, I have already stated that you are using wrong format specifier in the scanf(). In this part of your code:
for(i=0;i<m;i++){
for(j=0;j<50;j++){ // <====== Nested for loop
printf("please enter a string");
scanf("%s",&arr[i][j]);
// since the nested loop is supposed to run 50 times, assuming you are trying to read character by character and using %s format specifier
break;
// the nested loop will break in the first iteration itself unconditionally, do you really need nested loop here!
}
}
Check the inline comments. Hope this might give an idea of the mistakes you are doing.
Seems that you want to read string character by character using scanf(). If this is the case than make sure to take care of null terminating character because, in C, strings are actually one-dimensional array of characters terminated by a null character '\0'.
You can do:
#include <stdio.h>
void discard_extra_input() {
int c;
while((c = getchar()) != '\n' && c != EOF)
/* discard the character */;
}
int main(void){
int i,j,m;
printf ("Enter number of strings: ");
scanf("%d",&m);
discard_extra_input();
char arr[m][50];
for(i=0;i<m;i++){
printf("please enter string number %d: ", i+1);
for(j=0;j<49;j++){
scanf("%c",&arr[i][j]);
if (arr[i][j] == '\n') {
//need to add null terminating character manually
arr[i][j] = '\0';
break;
}
}
if (j==49) {
// In case where the input from user is more than 50 characters,
// need to add null terminating character manually.
arr[i][j] = '\0';
// discard the extra input when input from user is more than 50 characters.
discard_extra_input();
}
}
for(i=0;i<m;i++){
for(j=0;j<50 && arr[i][j]!='\0';j++){
printf("%c",arr[i][j]);
}
printf ("\n");
}
return 0;
}
The code is self explanatory except one thing - call to discard_extra_input() function after first input from user scanf("%d",&m);. Reason -
Look at the statement:
scanf("%c",&arr[i][j]);
the %c format specifier will consume the leftover newline character '\n' from the input stream due to the ENTER key pressed after first input by the user (number of strings input from user). Hence, in order to discard it, calling discard_extra_input() function. In the other place it has been used to discard the characters when user entered string of size more than 49.
Hope this helps.
I know the code. But looking for specific ans. Where the problem lies with the code
The problem is here:
scanf("%s",&arr[i][j]);
and here:
printf("%s", arr[i][j]);
This is the specific answer you are looking for.
%s won't do any bound checking. It adds the characters starting from the memory location arr + i * m + j to arr + i * m + j + (length of input) + 1 (one extra char for the additional null character that scanf appends). Take a sample input. Assume an arbitrary starting address for arr and do the maths.
Also consider any writes beyond the allocated space for arr leads to undefined behavior.
Similarly printf("%s", arr[i][j]); will try to start reading from the address arr[i][j] till it finds a null character. It would usually lead to crash of the code because if your string has ascii characters, the address would be too low to point to any valid user-mapped memory.
If your code is working, its mostly because you already have a UB in your scanf.
Get a pen and paper and do some dry runs
This is a pretty simple problem buddy. You've got the idea right actually, that you need to use 2d array to store strings. Just that the usage is slightly wrong.
First of all let me tell you how 2d arrays need to be used to store in c. In your 2-D array, you've got rows and columns. Say, row represented by i and columns by j, i.e, each row arr[i] contains j elements. So in your context, each row arr[i] contains each string of upto 50 chars. So scanf should be just for arr[i]. And you need to loop with for, m times to accept m strings.
Same applies to printing as well.
Here is the working code:
#include <stdio.h>
#include <stdbool.h>
int main(void){
int i,j,m;
printf("\nenter m value:");
scanf("%d",&m);
char arr[m][50];
for(i=0;i<m;i++){
printf("\nplease enter a string no %d: ", (i+1));
scanf("%s",arr[i]);
}
printf("\nthe strings are: \n");
for(i=0;i<m;i++){
printf("\n%s\n",arr[i]);
}
}
And the output in case you want to cross check:
OUTPUT:
enter m value: 3
please enter a string no 1: qwerty
please enter a string no 2: asdfgh
please enter a string no 3: zxcvbn
the strings are:
qwerty
asdfgh
zxcvbn

Taking strings as a 2-D char array

I want a code such that I enter some strings one-by-one (by pressing enter) and display it.
for example;
Input
abc
def
Output
abc
def
also I want this input to be in a array so that I can select any character
from the array whenever I want. For example: s[1][1] gives 'e'.
I have writen a code for this problem.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i, j, n, m;
scanf("%d%d", &n, &m);
char a[n][m];
for (i = 0; i<n; i++)
scanf("%s", a[i]);
for (i = 0; i<n; i++) {
printf("%s", a[i]);
printf("\n");
}
}
But for this code my input/output goes like this:
Input
ab
cd
Output
abcd
cd
Can anyone tell where am I going wrong?
You have not shown the input value of n and m in the question. But from the input and output string shown, it seems that char array a[i] does not have the enough space for terminating null-character \0. When you give format specifier %s, scanf() automatically adds a terminating null character at the end of the stored sequence. I tried your code with input 2 for both n and m and I am getting the output as you are getting:
$ ./a.out
2 2
ab
cd
abcd
cd
Give the value 4 to m and the output is:
2 4
ab
cd
ab
cd
When using scanf() for string input, it is good to add check for max character modifier that is 1 less than the length of the input buffer. So, if the size of input buffer is 4 then you can do
scanf("%3s",a[i]);
With this, the scanf() will read not more than 3 characters in a[i] and will add \0 at the fourth location of a[i]. Beware with this, it does not discard the remaining input from input stream and they will be consumed by consecutive scanf() call.
If you want to drop the extra input which wasn't consumed by scanf, one way of doing it is to read and discard the extra input using a loop, like this:
int c;
while((c = getchar()) != '\n' && c != EOF)
/* discard the character */;
You can add it after scanf() reads data from input stream, like this:
for(i=0; i<n; i++) {
scanf("%3s", a[i]); // assuming the size of a[i] is 4
int c;
while((c = getchar()) != '\n' && c != EOF) // <=== This loop read the extra input characters and discard them
/* discard the character */;
}
This will work fine for the input that does not contain any whitespace characters. If your input contain any whitespace character, it may not behave as expected. Hence, I would suggest you to read about fgets() which gives you better control for string input.
Check this: fgets
and this: How to read from stdin with fgets()?
you are working with a 2D array of char:
char a[n][m];
but keep in mind the value for the 2nd index should be 1 character longer than the length of the string you wish it to allow room for the \0 byte. (all C strings must be null terminated)
This means char a[n][m]; can contain up to n strings, each string with maximum length of m-1 bytes.
char exampleStr[] = {"char count"}; //for example contains 11 characters (not 10)
|c|h|a|r| |c|o|u|n|t|\0| //note nul char is appended
Another common problem when reading user input in a loop is failure to remove any unwanted newlines, which can cause the loop to behave poorly. Following is an example of how to read a user specified number of strings ( using fgets() instead of scanf() ), each with a user specified length: (also removing unwanted newlines ( \n ) in the process)
For readability, the following example replaces n & m with lines & maxLen.
int main(void)
{
int lines, maxLen, i=0;
printf("Enter number of lines:");
scanf(" %d", &lines);
printf("Enter maxLen line length:");
scanf(" %d", &maxLen);
char line[lines][maxLen+2]; //+2 to allow for trailing newline and null
fgets(line[i], maxLen, stdin);//consume anything left in stdout
printf("Enter up to %d characters and hit return:\n%d) ", maxLen, i+1);
for(i=0;i<(lines);i++)
{
fgets(line[i], maxLen, stdin);
line[i][strcspn(line[i], "\n")] = 0; // clear newline
printf("Enter up to %d characters and hit return:\n%d) ", maxLen, i+1);
}
return 0;
}
All strings in C must be terminated with the null character \0, print knows this and prints all character UP TO that sign. You should make all of your strings 1 character longer than the words you plan to fit in them and fill them with 0 (0 is the integer value of \0) in the start to avoid this problem.

Scanning in strings into a 2D array in C

I need to take an input of 20 words entered by the user put those into a 2D array and print that out
my current code is
char array2[20][20];
int i;
for(i=0;i<20;i++)
{
printf("enter a word\n");
scanf(" %[^\n]",array2[i]);
}
for(i=0;i<colsize2;i++)
{
printf("\n");
for(j=0;j<rowsize2;j++)
{
printf("%c",array2[i][j]);
}
}
(I have no idea what %[^\n] is but it works better than %c or %s)
there are no compiler errors and the program will run but when it prints the array after all the words have been entered all I get is complete garbage
like
aȪ(M▒awn-US▒ e▒(<▒▒t/▒▒▒(5h▒tr:▒(
qh▒tdle__000
HW5.exe▒`wauld▒(▒&Oe,▒*a▒+a▒▒
so much so that it takes a bit of scrolling to get back to the start of my program
I do have more in this program that's not in my question but I'm 99% sure it wouldn't mess with what I have here but if you do want to see the rest just ask
I literally just started programming so I don't know diddly squat about it yet so if you could keep that in mind when you answer also this is for a school assignment so it doesn't need to be perfect it just has to get the job done
thanks to whoever answers this I've been grappling with this for hours
The format string
" %[^\n]"
^ note the leading space
means that scanf will first read and discard any number of leading whitespace characters and then match any sequence of characters which does contain a newline. scanf can potentially overrun the buffer it save the string into if the input string is too large for the buffer invoking undefined behaviour. The %s format specifier means scanf skips the leading whitespace characters and reads the input string till it encounters a whitespace at which point it appends a terminating null byte to the buffer it writes into and then returns.
Therefore, what you need is
char array2[20][20];
int i;
for(i = 0; i < 20; i++)
scanf("%19s", array2[i]);
for(i = 0; i < 20; i++)
printf("%s\n", array2[i]);
Initialize your array to 0:
char array2[20][20] = { 0 } ;
And then print the string not every character:
for(i=0;i<20;i++)
{
printf("%s",array2[i]);
printf("\n");
}

Resources