Taking strings as a 2-D char array


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?





The input you have shown in question is missing the input value of n and m. Show the input value you are giving to n and m.
– H.S.
Jun 29 at 11:05


n


m


n


m





While with gcc and c99+ there is no problem with the Variable Length Array of Arrays char a[n][m];, note that not all compilers support them. After you have the basics handled, look at declaring/allocating a number of pointers (e.g. char **a = malloc (n * sizeof *a);), reading with a sufficiently large buffer (e.g. char buf[1024] = ""; scanf("%s", buf); (checking return)) and then allocating storage for each string (e.g. a[0] = malloc (strlen (buf) + 1); strcpy (a[0], buf);). This provides allocated storage for your strings, while providing access with string indexes, a[1][1],
– David C. Rankin
Jun 29 at 18:56



c99+


char a[n][m];


char **a = malloc (n * sizeof *a);


char buf[1024] = ""; scanf("%s", buf);


a[0] = malloc (strlen (buf) + 1); strcpy (a[0], buf);


a[1][1]




4 Answers
4



you are working with a 2D array of char:


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 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 a[n][m];


n


m-1


char exampleStr = {"char count"}; //for example contains 11 characters (not 10)

|c|h|a|r| |c|o|u|n|t|| //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)


fgets()


scanf()


n



For readability, the following example replaces n & m with lines & maxLen.


n


m


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





The extra line[i][strcspn(line[i], "n")] = 0 is useless as the %s conversion format reads words, not lines. It would be useful if you were reading lines with fgets() (a safer approach indeed) but you would need to define line as char line[lines][maxLen+2]; to allow for both the trailing newline and the null terminator.
– chqrlie
Jun 29 at 15:56



line[i][strcspn(line[i], "n")] = 0


%s


fgets()


char line[lines][maxLen+2];





@chqrlie - Good feedback. Edited suggestions in.
– ryyker
20 hours ago



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


n


m


char


a[i]



%s


scanf()


2


n


m


$ ./a.out
2 2
ab
cd
abcd
cd



Give the value 4 to m and the output is:


4


m


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


1


4


scanf("%3s",a[i]);



With this, the scanf() will read not more than 3 characters in a[i] and will add 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.


scanf()


3


a[i]



a[i]


scanf()



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:


scanf()


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.


fgets()



Check this: fgets
and this: How to read from stdin with fgets()?



Consider using fgets to capture input. In this case it is difficult to restrict scanf to the number of characters allowed by m. fgets takes care of that but remember that the newline is one of the characters counted by fgets.


fgets


scanf


m


fgets


fgets


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main( void)
{
int i = 0;
size_t n = 0, m = 0;
int scanned = 0;
char values[100] = "";

do {
printf ( "enter two values as x y ( x > 0 and y > 2)n");
if ( fgets ( values, sizeof values, stdin)) {
scanned = sscanf ( values, "%zu%zu", &n ,&m);
}
else {
fprintf ( stderr, "problem fgetsn");
return 0;
}
} while ( scanned != 2 || n < 1 || m < 3);

char a[n][m + 2];//+2 for newline and ''

i = 0;
do {
printf ( "enter string %zun", i + 1);
if ( !fgets ( a[i], m + 2, stdin)) {
fprintf ( stderr, "problem fgetsn");
return 0;
}
if ( !strchr ( a[i], 'n')) {//string does not have newline
printf ( "enter no more than %zu charactersn", m);
while ( !strchr ( a[i], 'n')) {//call until newline is found to clear input
if ( !fgets ( a[i], m + 2, stdin)) {
fprintf ( stderr, "nfgets problemn");
return 0;
}
}
}
else {
i++;
}
} while ( i < n);

for(i=0;i<n;i++){
printf("%s",a[i]);
}
}





Using type size_t for n and m instead of int is overkill and counterproductive as many environments still do not support the %zu conversion specification. Moreover, you use int for i...
– chqrlie
Jun 29 at 16:02


size_t


n


m


int


%zu


int


i



All strings in C must be terminated with the null character , 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 ) in the start to avoid this problem.







If I try doing that my output of other strings stops as well for example: Input abc def If I make s[3]=''; output abc ..
– Ayaz S Imran
Jun 29 at 11:00






What is s[3], you mean a[i][3], which should be a[i][m-1] in general?
– Qubit
Jun 29 at 11:07



a[i][m-1]





scanf("%d%d",&n,&m); char a[n][m]; for(i=0;i<n;i++) for(j=0;j<m;j++) scanf(" %c",&a[i][j]); In the scanf, when I used a gap before %c, my code worked fine. Without the gap, it doesn't work. why?
– Ayaz S Imran
Jun 29 at 11:14





@AyazSImran - the gap in " %c" consumes the newline character, which can poor loop behavior. There are other methods to do this as well. (see above)
– ryyker
Jun 29 at 13:18



" %c"






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Comments

Popular posts from this blog

paramiko-expect timeout is happening after executing the command

Opening a url is failing in Swift

Export result set on Dbeaver to CSV