Problem with 2D char arrays, program does not print - c

I'm struggling with 2D char arrays, I want to create a list of trains, but it seems that something is wrong here since after I've registered 7 names the program will automatically close... Can somebody help me and explain me how to write the program correctly everytime? Thanks.
**NOTE:***the code is not finished yet*
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 7
#define M 20
int main()
{ FILE *fp;
fp=fopen("Lines.txt","w");
int i,n;
char trains[N][M];
char train[M];
for(n=0;n<N;n++)
{
scanf("%s", train);
strncpy(trains[n],train,M-1);
}
for(n=0;n<N;n++)
{
for(i=0;i<M;i++)
{
printf("%s\n", trains[n][i]);
}
}
return 0;
}

having
char trains[N][M];
the printf in
for(i=0;i<M;i++)
{
printf("%s\n", trains[n][i]);
}
in invalid because trains[n][i] is a char and you print it as a string (%s)
All the form including the for can be replaced by
printf("%s\n", trains[n]);
Else you can write char by char but you need to stop when you reach the null char :
for(i=0; trains[n][i] != 0 ; i++)
{
printf("%c", trains[n][i]);
}
putchar('\n');
You open a file but you do not write in
You need to test the result of the fopen to check the file was open
Other problem in
scanf("%s", train);
strncpy(trains[n],train,M-1);
The strncpy does not copy the final null char
Because you have
char trains[N][M];
char train[M];
To use the intermediate train is useless and does not offer a protected (its size if not longer than trains[x])
You need to check the return value of scanf, and to read up to 19 characters (M - 1) you can do that :
if (scanf("%19s", trains[n]) != 1)
break;
You do not have the guarantee you read 7 trains so you have to change the loop after :
for (i = 0; i != n; ++i)
printf("%s\n", trains[n]);
You can also use puts in that case
And if you want to also write in the open file
for (i = 0; i != n; ++i) {
fprintf(sp, "%s\n", trains[n]);
puts(trains[n]);
}
Finally your program can be
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 7
#define M 20
int main()
{
FILE * fp=fopen("Lines.txt","w");
if (fp == 0) {
puts("cannot open Lines.txt");
return -1;
}
int i,n;
char trains[N][M];
for(n = 0; n<N; n++)
{
if (scanf("%19s", trains[n]) != 1)
break;
}
for(i = 0; i != n; ++i)
{
fprintf(fp, "%s\n", trains[i]);
/*puts(trains[i]);*/
}
fclose(fp);
return 0;
}
Compilation and execution :
pi#raspberrypi:/tmp $ gcc -g -pedantic -Wextra c.c
pi#raspberrypi:/tmp $ ./a.out
train1
train2
train3
train4
train5
train6
train7
pi#raspberrypi:/tmp $ cat Lines.txt
train1
train2
train3
train4
train5
train6
train7
pi#raspberrypi:/tmp $
Note if the name of a train has more than 19 characters it will be cut, example :
pi#raspberrypi:/tmp $ ./a.out
train1
verylongnameofatrain
train3
train4
train5
train6
pi#raspberrypi:/tmp $ cat Lines.txt
train1
verylongnameofatrai
n
train3
train4
train5
train6
pi#raspberrypi:/tmp $

for(n=0;n<N;n++)
{
for(i=0;i<M;i++)
{
printf("%s\n", trains[n][i]);
}
}
should be
for(n=0;n<N;n++)
{
printf("%s\n", trains[n]);
}
This is because in your char array trains, each row contains the string entered by you. When you do trains[n][i], it tries to access a particular character inside the string.
If you want to print each character, try like below:
for(n=0;n<N;n++)
{
for(i=0;i<M && trains[n][i]!='\0';i++)
{
printf("%c", trains[n][i]);
}
printf("\n");
}

Related

Why cant the loop be terminated in my code?

This a reverse string code but the loop cant be terminated and keeps taking input
How can I terminate it
#include <stdio.h>
#include <string.h>
#define len 100
int main() {
char str[len];
int i;
do {
gets(str);
for (i = (strlen(str) - 1); i > -1; i--) {
printf("%c", str[i]);
}
printf("\n");
} while (str[0] != '\0');
return 0;
add str[0]='\0'; before gets and its done. this is because making a loop termination and to get out of the loop after clicking enter.
#include <stdio.h>
#include <string.h>
#define len 100
int main() {
char str[len];
int i,lenh;
do{
str[0]='\0';
gets(str);
lenh=strlen(str);
for(i=lenh-1;i>=0;i--)
{
printf("%c",str[i]);
}
printf("\n");
}while(str[0]!='\0');
return 0;
}
now, there are a few points (answer code below)
Basically, you are printing hand-to-hand with input, while the question states of a multi line input. So, first you have to take all the inputs and then output will be shown.
Your original code does not keep taking input as you have said. Question says the last string is empty string. You press enter in empty string, your above code will terminate.
Remember Last Input String Should be Empty, that's termination condition
#include <stdio.h>
#include <string.h>
int main(){
char str[100];
char stringArray[50][100]={0};
int k,m,count=0,i=0,j=0;
do {
fgets(str,100,stdin);
k=strlen(str);
for(m=0;m<k-1;m++){
stringArray[count][k-m-2]=str[m];
}
count++;
}
while (str[0] != '\n');
for(i=0; i<count; i++){
for(j=0;stringArray[i][j]!=0;j++){
printf("%c",stringArray[i][j]);
}
if(i<count-1){
printf("\n");}
}
return 0;
}
sample input
Hello team Loop
Welcome
sample output
pooL maet olleH
emocleW

Do-While didn't loop back but let the value pass through

I tried to make a program to add a string to a set of strings but the checking for existing string part didn't work. It just passes the do-while and add straight into the list.
void Add(char index[MAXN][24], int *pi)
{
char name[24];
int n, name_check;
do {
printf("Add a student : ");
fflush(stdin);
scanf("%23[^\n]", name);
name_check = 1;
for (n = 0; n < *pi; n++)
if (strcmp(name,index[n]) == 0)
{
printf("Existing name found.\n");
name_check = 0;
n = *pi - 1;
}
} while (!name_check);
strcpy(index[*pi], Trim(name));
(*pi)++;
printf("Added.\n");
}
your problems comes from that line :
scanf("%23[^\n]", name);
you read the name up to the newline, the newline is not read, and because fflush(stdin); does nothing the newline is still available, so after you read one name in the very first call of Add the next times the input contains just the newline and nothing is read, so you use name not initialized with an undefined behavior
replace the line by
scanf(" %23[^\n]", name);
doing that you bypass the possible newline and also the other spaces starting the input, that also have the great advantage to not limit the length of the read name to 13 in case the input start by 9 spaces
doing the minimum, so removing the useless fflush and modifying the format of the scanf and adding a Trim doing nothing :
#include <stdio.h>
#include <string.h>
char * Trim(char *s)
{
return s;
}
#define MAXN 10
void Add(char index[MAXN][24], int *pi)
{
char name[24];
int n, name_check;
do {
printf("Add a student : ");
scanf(" %23s", name);
name_check = 1;
for (n = 0; n < *pi; n++)
if (strcmp(name,index[n]) == 0)
{
printf("Existing name found.\n");
name_check = 0;
break;
}
} while (!name_check);
strcpy(index[*pi], Trim(name));
(*pi)++;
printf("Added.\n");
}
int main()
{
char index[MAXN][24];
int p = 0;
int i;
Add(index, &p);
Add(index, &p);
for (i = 0; i != p; ++i)
puts(index[i]);
return 0;
}
Compilation and execution:
/tmp % gcc -Wall d.c
/tmp % ./a.out
Add a student : aze
Added.
Add a student : aze
Existing name found.
Add a student : qsd
Added.
aze
qsd
/tmp %
I encourage you to always check the value of scanf, if you did you was able to detect it returns 0 except the very first time and you found your error.
an other problem occurs, the spaces at the end of the name are not removed by scanf, immediately after you read the name you need to trim it then to compare it with the memorized names. In your code if we forget the newline not flush and you enter "aze" then "aze " etc you will save two times "aze" (of course all inputs without the '"')
Out of that your program can be simplified, for instance you do not need name because you can read in index[*pi] directely and save the strcpy, name_check is also useless because you can check the value of n after the loop or move the end of the function into the loop then return etc.

Debug assertion failed, Expression: (unsigned)(c + 1) <=256

What I am trying to do:
Make a program that opens a file and read the content (mostly characters)
Example on what it should do:
The file contains "ABA", It should print: Letter A Count 2 || Letter B Count 1
but I am getting this error when I start debugging http://imgur.com/a/zvpWg
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <ctype.h>
struct arr
{
char letter;
int count;
};
void main ()
{
arr s[7];
char letter;
FILE *fp;
fp=fopen("D:\\data.txt","r");
if(fp==NULL)
{
printf("Error File Not Found\n");
getch();
exit(1);
}
while(fscanf(fp,"%ch",&letter)!=EOF)
{
for(int i=0;i<7;i++)
{
if(!isalpha(s[i].letter))
{
s[i].letter=letter;
s[i].count=1;
break;
}
else if(s[i].letter == letter)
s[i].count++;
break;
}
}
for(int h=0;h<7;h++)
printf("Letter: %c Count: %d ||",s[h].letter,s[h].count);
getch();
}
Where am i wrong exactly ?
The Problem might be -
function isalpha() is being called with an integer whose value is not a single byte i.e. 0-255.

C - making this program portable

The idea
scanning a password entered by the user and showing ********** in place of P#$$w00r_D
explaining the code
inside a while loop keep scanning the characters using getch() and put them into an array password[], until the user press return
The Code
#include <stdio.h>
#include <conio.h>
#define TRUE 1
#define P_MAX 25
int main(int argc, char* argv[]) {
char password[P_MAX], ch;
int i = 0;
puts("Enter the password [MAX 25]: ");
while (TRUE) {
if (i < 0) {
i = 0;
}//end if
ch = getch();
if (ch == 13)//return
break;
if (ch == 8) // BACKSPACE
{
putch('b');
putch(NULL);//Overwrite that character by NULL.
putch('b');
i--;//Decrement Current Track of Character. (i)
continue;
}//end if
password[i++] = ch;
ch = '*';
putch(ch);
}//end while
printf("\nPassword Entered : %s", password);//test
getch();
return 0;
}//end main
Compiling on Unix machine
[ar.lnx#host Documents] $ gcc 115.c -o x
115.c:2:18: fatal error: conio.h: No such file or directory
compilation terminated.
[ar.lnx#host Documents] $
this code works fine on windows, but not in Unix.
any help?

How to format input to only accept integer values

input value 123 -- this value is integer, and valid
input value 1b23a -- this value is invalid
How do I detect which values are valid and not?
Here is my code:
#include <stdio.h>
#include <conio.h>
void main()
{
char str1[5],str2[5];
int num,num1,i;
num=0;
clrscr();
printf("Enter the Number ");
scanf("%s",str1);
for(i=0;str1[i]!='\0';i++)
{
if(str1[i]>=48&&str1[i]<=56)
num=num1*10+(str[i]-48);
else
{
printf("The value is invalid ");
}
}
printf("This Number is %d",num);
getch();
}
Please see this answer regarding use of strtol(). It is a safe way to convert arbitrary input that should be a string representation of an integer, while also saving 'garbage' bytes for additional analysis.
Using it, your code would look something like this:
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#ifdef LINUX_VERSION
#include <curses.h>
#else
#include <conio.h>
#endif
#define BUFF_SIZE 1024
int main(void)
{
char str1[BUFF_SIZE], *garbage = NULL;
long num = 0;
printf("Enter the Number ");
scanf("%s",str1);
errno = 0;
num = strtol(str1, &garbage, 0);
if (errno) {
printf("The number is invalid\n");
return 1;
}
printf("You entered the number %ld\n", num);
if (garbage != NULL) {
printf("Additional garbage that was ignored is '%s'\n", garbage);
}
getch();
return 0;
}
This doesn't fix everything that is questionable about what you posted, but it should help you get off to a better start.
Output is:
tpost#tpost-desktop:~$ ./t
Enter the Number 1234abdc
You entered the number 1234
Additional garbage that was ignored is 'abdc'
Compiled via:
gcc -Wall -DLINUX_VERSION -o t t.c -lcurses
I'm not sure what platform you are using, so additional fixes to the code may be needed.
#include<stdio.h>
#include<conio.h>
void main()
{
char str1[5],str2[5];
int num,num1,i;
num=0;
clrscr();
printf("Enter the Number ");
scanf("%s",str1);
for(i=0;str1[i]!='\0';i++)
if(str1[i]>=48&&str1[i]<=56)
num=num1*10+(str[i]-48);
else
{
printf("The value is invalid ");
}
}
printf("This Number is %d",num);
getch();
}
One way is to use sscanf and check that there are no characters following the number. This is done most easily by adding a %c on the end and testing the return code, like this:
const char *yourString = ...;
int theValue, dummy;
if (sscanf(yourString, "%d%c", &theValue, &dummy) == 1) {
// Was a pure number, parsed into 'theValue'
} else {
// Either no number or had junk after it
}

Resources