I'm iterating through a loop. On the first iteration, i can write on the stdin and get the data I want. on the second operation: name is skipped, and it asks me for name2. Why is it skipping name?
for (i = 0; TRUE; i++) {
printf("> nom :");
fgets(items[i].name, 15, stdin);
printf("nom: %s\n", items[i].name);
if (items[i].name[0] == '.') break;
printf("> prenom : ");
fgets(items[i].name2, 15, stdin);
printf("name2: %s\n", items[i].name2);
}
The code you presented does not prompt for the name, even on the first iteration of the loop. If you get any prompting for it at all then that is happening before entering the loop. In contrast, the code presented does prompt for name2.
Each iteration of the loop begins by reading the next name (without prompting) and printing it. If you see different behavior then you are running different code.
Related
my code is to show a few questions that are contained in a file when the user select the option to.
But i'm facing this problem: After de program show 2 questions it always shows only the last line of my file.
I don't know what is wrong.
Here is the code (only de case 1 of the switch menu)
printf("\nThe selected subject was Geology");
while(continue != 0)
{
r=0;
srand(time(NULL));
r = rand()%7;
printf("\n%d", r);
if(r==0)
r=1;
for(i=0; i<r; i++)
fscanf(arqgeo, "%s %s %s %s %s %c", question, alta, altb, altc, altd, &respa);
printf("\n\n%s \n%s \n%s \n%s \n%s \n", question, alta, altb, altc, altd);
printf("Enter alternative: ");
setbuf(stdin,NULL);
scanf("%c",&resp);
if(arqgeo == NULL)
{
printf("An error has occurred\n");
printf("Contact the developers !!!\n");
} else {
if(resp == respa)
{
printf("You're right!!!\n");
pont++;
printf("\n\n\n");
} else {
puts("\a");
printf("You missed!!!");
printf(" The correct answer is: %c", respa);
erro++;
printf("\n\n\n");
}
}
printf("Do you wish to continue? Enter a number other than 0 ");
scanf("%d", &continue);
}
break;
where: "respa" is the right answer, "alta-d" is the alternatives, "resp" is the answer of the user, "arqgeo" is the file that contain the questions
--sorry for the bad english--
Adding to Jonathan Leffler's and my earlier comments.
Each iteration reads some lines from the file. The first iteration works fine but the second picks up where the first left of so you blow through a lot of lines quickly.
What is needed is to rewind the file to the beginning at the start of each iteration. The fseek() function will do this for you. The trouble is you will also repeat questions if rand() % 7 returns the same number again. A static array initialized to all zeros to check if an question has already been used would be needed. Or use a bit map. rewind() is a special case of fseek() that returns to the start of the file (think old-style magnetic tapes).
Also, if(arqgeo == NULL) is wrong as the value of apqgeo does not change on troubles. Look at the ferror() and feof() functions to test eof/error conditions. scanf() also returns the count of the fields converted with EOF indicating some type of trouble where these "f" functions would be useful. At any rate returns of <= 0 indicate time to get out (EOF is usually (-1)).
While it's annoying to have to test each and every input statement for troubles it is good practice. If you don't you need to be hyper alert for behaviors caused by silent errors.
Challenge: arrange question file and and it's handling to get rid of the r == 0 test. If you have 8 questions you really don't need it.
I am trying to make a program which will store the data entered by the user in a text file whose name is provided by the user. Program will terminate when the user enters exit. strcmp function of string.h is used for string comparison and fgets() is used to read data from stdin.
Here is my code.
#include<stdio.h>
#include<string.h>
void main()
{
char file[60]; // will store file name
printf("Enter file name: ");
fgets(file, 59, stdin);
FILE *fp = fopen(file, "a+"); // open file in append mode
if(fp == NULL){
printf("File not found !");
return;
}
char data[100];
printf("Enter some data to add to file(exit to terminate): ");
fgets(data, 99, stdin);
int flag = strcmp(data, "exit");
while(flag != 0){
fputs(data, fp);
fgets(data, 59, stdin);
flag = strcmp(data, "exit");
printf("%d\n", flag); // for checking whether string are correctly comapred or not
}
printf("Bye");
}
Program does not terminate even if i enter exit. I have also tried concatenating "\n" at the end of string input by user but that also doesn't help. Although, gets() function works fine, but i know it is not preferred to use to I shifted to fgets() but it doesn't work for me.
Check the man page for fgets(), it reads and stores the newline (caused by pressing ENTER) after the entered input. Thus, the strcmp() fails.
You have to manually strip the input buffer off the newline, before you can compare the input. A simple yet elegant way of doing that would be
data[strcspn(data, "\n")] = 0;
fgets reads in a complete "line", i.e. a sequence of characters until (and including!) a new line character. Hence, when a user presses "Enter", the new line will be part of the string read in and a strcmp(data,"exit") will evaluate to "not equal".
So either strip off the new line before comparison, or compare with a string literal including a new line. Since you write the data as is(i.e. including the new lines) to a file, it seems cumbersome to first strip the new line off and add it then in the output manually. So I'd actually suggest the second approach:
fgets(data, 100, stdin);
flag = strcmp(data, "exit\n");
An alternative would be to use strstr if excess characters do not matter (i.e. your program would exit if the user types "exit" or "asdfexitasdf". - both of which contain "exit".)
So
int flag = strstr(data, "exit");
if(flag != NULL)
//exit the program
else
//stay in the program
I am currently working on an practice. My program is working and I just want to make it more robust and foolproof. The code is of the following:
printf("Enter Name : ");
memset(userinput, '\0', 50);
fgets(userinput, 50, stdin);
I accidentally hit the enter key(newline) and for my program, the system just dangle there and couldn't accept anymore inputs. I am only allowed to use fgets. So is there any way of rejecting \n from being entered as a field?
One way you could do it is to check if the first character is a newline:
do {
printf("Enter Name : ");
memset(userinput, '\0', 50);
fgets(userinput, 50, stdin);
}
while ( userinput[0] == '\n');
printf("Hello %s", userinput);
This would still leave you up to space + newline, but its a first start.
So is there any way of rejecting \n from being entered as a field?
... to make it more robust and foolproof.
Code should not prevent '\n' from being read via fgets(). Instead, code should assess that input for validity. A leading '\n' is likely only 1 concern. Make code easy to update as certainly the criteria for a valid name will evolve.
I recommend a separate name test.
bool ValidNameInputTest(const char *userinput) {
if (*userinput == '\n') return false; // fail
// add other tests as needed
return true;
}
In a loop, test and repeat as needed. Code should exit the loop on success. When an end-of-file or input error occurs, code should detect/handle that too.
...
char userinput[50];
do {
printf("Enter Name : ");
fflush(stdout); // add to insure above output is seen before reading input
//memset(userinput, '\0', 50);// Commented out as not needed - although useful for debug
// Check return value and used a derived size
//fgets(userinput, 50, stdin);
if (fgets(userinput, sizeof userinput, stdin) == NULL) {
Handle_EndOfFile_or_Error();
}
} while (!ValidNameInputTest(userinput));
So i have some code that will allow the user to write anywhere they want inside a text file, thanks to the answers from How do I write to a specific line of file in c? , However i have hit a new obstacle, whenever i write back to the file an annoying random character will always appear at the end of the last word, and if it's on the first line a new line is created before it.
I know this has something to do with the file copy but i don't know where, can someone please help?
int main()
{
FILE *fp,*fc;
int lineNum;
int count=0;
int ch=0;
int edited=0;
char t[16];
fp=fopen("start.txt","r");
fc=fopen("end.txt","w");
if(fp==NULL||fc==NULL)
{
printf("\nError...cannot open/create files");
return 1;
}
printf("\nEnter Line Number Which You Want 2 edit: ");
scanf("%d",&lineNum);
while((ch=fgetc(fp))!=EOF)
{
if(ch=='\n')
count++;
if(count==lineNum-1 && edited==0)
{
printf("\nEnter input to store at line %d:",lineNum);
scanf(" %s[^\n]",t);
fprintf(fc,"\n%s\n",t); /
edited=1;
while( (ch=fgetc(fp))!=EOF )
{
if(ch=='\n')
break;
}
}
else
fprintf(fc,"%c",ch);
}
fclose(fp);
fclose(fc);
if(edited==1)
{
printf("\nCongrates...Error Edited Successfully.");
FILE *fp1,*fp2;
char a;
system("cls");
fp1=fopen("end.txt","r");
if(fp1==NULL)
{
puts("This computer is terrible and won't open end");
exit(1);
}
fp2=fopen("start.txt","w");
if(fp2==NULL)
{
puts("Can't open start for some reason...");
fclose(fp1);
exit(1);
}
do
{
a=fgetc(fp1);
fputc(a,fp2);
}
while(a!=EOF);
fclose(fp1);
fclose(fp2);
getch();
}
else
printf("\nLine Not Found");
return 0;
}
(Sorry about ident, i'm in a rush)
Try changing your do-while loop like,
while((a=fgetc(fp1))!=EOF)
fputc(a,fp2);
I guess it will solve your problem.
do
{
a=fgetc(fp1);
fputc(a,fp2);
}
while(a!=EOF);
A do-while loop evaluates its condition after performing the body of the loop. In other words, this loop is writing EOF to the file, which you shouldn't be doing. EOF isn't actually a character, it's just something that gets returned by the OS when it's finished reading a file. I'm not sure what would be the end result of actually writing EOF to a file, but I'd hazard a guess this is what's causing the "annoying random character" you're talking about.
Invert the loop into a normal while loop, as follows, so that you're checking for EOF before writing anything:
while ((a=fgetc(fp1))!=EOF)
{
fputc(a,fp2);
}
1) As you said "and if it's on the first line a new line is created before it"
To solve this problem you have to optimize the use of fprintf(fc,"\n%s\n",t); statement.
Replace this fprintf(fc,"\n%s\n",t); with below code.
if(count==0) //if its the first line to edit..
fprintf(fc,"%s\n",t) //watch closely,no '\n' before %s,This will copy wihtout creating new line at beginning of line or file.
else
fprintf(fc,"\n%s\n",t);
2) And Your statement scanf(" %s[^\n]",t); will not work properly if you give multiple-words input.You have tried to use both ScanSet and %s fromat specifer. You should only use any one of them.
Lets understand with a code snippet:-
char t[16]="\0";
scanf(" %s[^\n]",t); //Assume that you gave input "abc efg" from keyboard
printf("%s",t); // This will output only "abc" on moniter.
You should change it to some thing like this:-
char t[16]="\0";
scanf(" %15[^\n]",t);//here 15 is sizeof(array)-1. one left to accomadate '\0'.
printf("%s",t); //this will successfully output "abc efg" (if given)
I'm writing a program that acts as a simple shell. Users call the program from the command line and are prompted to enter commands that are sent to the OS for completion. It should run until the user enters "done", at which point the program should break. I'm running into a problem with entering done - the program quits as it should, but prints
sh: -c: line 0: syntax error near unexpected token `done'
sh: -c: line 0: `done'
to the terminal before finishing execution. Here's the code I've written that applies:
char isDone[] = "done\n"; //fgets stores the new line character from the command line
do {
printf(">>"); //print the prompt each time through the loop
fgets(command, 50, stdin); //get a line from the terminal
system(command);
} while (strcmp(command, isDone) != 0); //break the loop if the user types in done
I think the error has to do with the fact "done" is not a valid UNIX command, but I'm not sure how to deal with this error. I tried solving this problem with the following fix:
if(system(command) == -1){
printf("The OS doesn't recognize this command");
}
else
system(command);
But that didn't solve the problem or printing the errors to the screen, and created a second problem of printing the commands/errors twice - once in the if conditional block, and once in the else block. How can I solve this problem?
EDIT
This is a homework question the requires using a do-while. Is there a solution that uses a do-while?
The do...while construct executes its body before the loop condition is checked. So by the time the loop "realizes" that the user entered done, it has already tried to execute that input as a command inside the loop body.
The clearest way to fix this is to use break:
while (1)
{
fgets(command, 50, stdin);
if (!strcmp(command, isDone)) break;
system(command);
}
The reason to structure it this way is that each iteration consists of both actions that should be done before the condition (reading in the user input) and actions that should be done after the condition (executing the command with system()). Because of this, neither a do...while or simple while will allow you to structure your code intuitively. The break keyword gives you a way to put the loop's termination condition in the middle of the loop body.
The order of execution is:
fgets(command, 50, stdin); //get a line from the terminal
system(command);
strcmp(command, isDone) != 0
So the line "done" is read, sent to system (which tries to execute it as a shell command, printing an error) and only then it checks it.
You can try something like that:
for(;;){
printf(">>"); //print the prompt each time through the loop
fgets(command, 50, stdin); //get a line from the terminal
if(!strcmp(command, isDone)) break; //break the loop
system(command);
}
Edit: if you want to keep the do-while:
printf(">>"); //print the prompt each time through the loop
fgets(command, 50, stdin); //get a line from the terminal
do {
system(command);
printf(">>"); //print the prompt each time through the loop
fgets(command, 50, stdin); //get a line from the terminal
} while (strcmp(command, isDone) != 0); //break the loop if the user types in done
But the break version is clearly more readable.
After the fgets(), do the system() call inside an if statement:
if ( strcmp( isDone, command) != 0 ) {
system( command );
}