I'm creating a file management program for a project in C and I have this error which is probably obvious to most programmers but since I'm really bad I can't spot what I have done wrong. My main program is an interface which asks users for a file name and assigns it to the array fileName.
int main() {
char fileName[50];
assignFileName(fileName);
char option[2];
int checkInput;
do {
printf("File management program. Options :\n '1' for File operations (Create, copy, delete or display file)\n '2' for Line operations (Append, delete, display or insert line to file)\n '3' for General operations (Display change log or number of lines for file)\n '4' to select a new file\n '9' to exit program\n");
printf("aaa %s\n", fileName); //first printf check - prints "aaa" and value in fileName
checkInput = checkUserInput(option);
printf("aaa %s\n", fileName); // second printf check = prints only "aaa"
if (checkInput == 1) {
//... etc
}
void assignFileName(char *fileName) {
printf("Enter file name to operate on, or 'E' to exit the program.\n");
do {
if ((fgets(fileName, 50, stdin)) != NULL) {
if (fileName[strlen(fileName)-1] = '\n') {
fileName[strlen(fileName)-1] = '\0';
}
if (strlen(fileName) == 1 && *fileName == 'E') {
exit(0);
} else if (strlen(fileName) == 0) {
printf("Error : Please enter a file name or 'E' to exit.\n");
}
} else {
perror("Error assigning file name ");
}
} while (strlen(fileName) == 0);
}
I'm fairly sure this code is fine. There's probably lots of ways to make it more efficient and if anyone wants to offer their input I will take it into account. However, the problem is later on in the code. I have 2 printf statements to check the value of fileName. After the first one, everything seems to be alright but then the for the second one the value of fileName seems to be cleared, so something is clearly happening in checkUserInput. All checkUserInput does is check the user enters a single digit number :
void flush() {
int ch;
while ((ch = getchar()) != '\n' && ch != EOF) {
}
}
int checkUserInput(char *input) {
if (fgets(input, 3, stdin) != NULL) {
printf("you entered %c\n", input[0]);
if (input[1] == '\n') {
return 1;
} else {
flush();
printf("Error : Please enter one of the options given.\n");
}
} else {
printf("Error : Please try again.\n");
}
return 0;
}
I put more printf statements to error check and it seems after the call to fgets(input, 3, stdin) the value in fileName is cleared. Can anyone explain to me why this is the case? I'm not even passing the array fileName to checkUserInput so I don't even know how the program is changing it. This is a link to what the console displayed : (can't post images sorry not 10 rep).
https://cdn.discordapp.com/attachments/708320229737889832/802557193043050516/unknown.png
All help would be very appreciated. Thanks.
if (fileName[strlen(fileName)-1] = '\n') should be:
if (fileName[strlen(fileName)-1] == '\n')
Note that you can strip the trailing newline with this simple line:
filename[strcspn(filename, "\n")] = '\0';
error was char option[2] when it should be char option[3]. Thanks to #Nate Eldredge and #M Oehm
Related
I'm creating two programs that form a game and will be communicating with each other where one of them is essentially a user, but I'm starting off with building one and typing myself to this first program.
I want to input commands such as 'turn d1d2d3d4d5d6' (where the di are dice rolls), 'rerolled d1d2d3d4d5d6' and so forth, theres a bunch of commands. I want my program called player to take these commands and they'll do something with it.
Just to begin with I'm trying to take the input using stdin and putting it in array, then checking the array to see if its a valid command. However I can't seem to use fgetc and the array correctly. What i'm doing currently is just to take the input, put into an array and print it.
I don't actually want it to be 128 size array, I want it to be completely adjustable but I don't know how to do this with fgets. The if loop to check if its NULL is to find out if an array is empty but that's defintely wrong, not sure what to put in place there.
while(1){
int i = 1;
char* command[128];
fgets(command, 128, stdin);
for (i=0; i < 128; i++){
if (command[i] == NULL){
printf("%c\n", command[i]);
}
}
return 0;
}
So to be specific my main goal right now is take a command such as 'eliminated p' from the user and command becomes command=["eliminated","p"]
sample code:
#include <stdio.h>
#include <string.h>
int main(void) {
while(1){
char command[128];
if(NULL == fgets(command, sizeof command, stdin))//or use getline
break;
if(strchr(command, '\n') == NULL){//Too long
printf("Too long\n");
while(getchar() != '\n')
;//clear input
continue;
}
char *operation = strtok(command, " \t\n");
if(operation == NULL){
printf("Empty command\n");
continue;
}
char *operand = strtok(NULL, " \t\n");;
if(operand == NULL){
printf("Empty operand\n");
continue;
}
printf("operation:%s\noperand:%s\n", operation, operand);
char *commands[] = {operation, operand};
//do stuff
}
return 0;
}
Here is my code:
#include "game.h"
#define LINEINPUT 30
int loadMainMenu(void);
void playGame()
{
Cell board[BOARD_HEIGHT][BOARD_WIDTH];
char input[LINEINPUT + EXTRA_SPACES];
printInstructions();
while( getchar() != '\n' );
initialiseBoard(board);
while(TRUE)
{
displayBoard(board, NULL);
printf("At this stage of the program, only two commands are acceptable:\n");
printf("load <g>\n");
printf("quit\n");
fgets(input, LINEINPUT , stdin);
if(input[strlen(input) - 1] != '\n')
{
printf("BUFFER OVERFLOW\n");
readRestOfLine();
EXIT_FAILURE;
continue;
}
if(strcmp(input, "test") == 0)
{
printf("success!\n");
continue;
}
if(strcmp(input, "load 1") == 0)
{
printf("lfdsfsdfoad");
loadBoard(board, BOARD_1);
continue;
}
if(strcmp(input, "load 2") == 0)
{
loadBoard(board, BOARD_2);
continue;
}
if(strcmp(input, "quit") == 0)
{
loadMainMenu();
break;
}
}
}
i have cut it down so that it doesn't take up too much space. I was editing some of it this morning trying to fix things up and somehow, it doesnt read my inputs anymore. Well it does read my inputs but doesnt use strcmp to check if input matches and run the functions in the if statements. It was working fine previously but i did not change anything much.
As evidenced by your first if statement, fgets() returns strings with the \n line ending present. You'll want to either strip off that character, or add it to the strings you're testing against.
This question already has an answer here:
C file handling query
(1 answer)
Closed 9 years ago.
So I have a program that takes user input and compares it to a specific line in a file, however the final line will always be credited as incorrect, so can someone solve this for me?, thanks.
File content (just a list of random words)
Baby
Milk
Car
Face
Library
Disc
Lollipop
Suck
Food
Pig
(libraries are stdio,conio and string)
char text[100], blank[100];
int c = 0, d = 0;
void space(void);
int main()
{
int loop = 0;
char str[512];
char string[512];
int line = 1;
int dis = 1;
int score = 0;
char text[64];
FILE *fd;
fd = fopen("Student Usernames.txt", "r"); // Should be test
if (fd == NULL)
{
printf("Failed to open file\n");
exit(1);
}
do
{
printf("Enter the string: ");
gets(text);
while (text[c] != '\0')
{
if (!(text[c] == ' ' && text[c] == ' '))
{
string[d] = text[c];
d++;
}
c++;
}
string[d] = '\0';
printf("Text after removing blanks\n%s\n", string);
getch();
for(loop = 0;loop<line;++loop)
{
fgets(str, sizeof(str), fd);
}
printf("\nLine %d: %s\n", dis, str);
dis=dis+1;
str[strlen(str)-1] = '\0';
if(strcmp(string,str) == 0 )
{
printf("Match\n");
score=score+2;
}
else
{
printf("Nope\n");
score=score+1;
}
getch();
c=0;
d=0;
}
while(!feof(fd));
printf("Score: %d",score);
getch();
}
For any input on the last line, the output will always be incorrect, I believe this is something to do with the for loop not turning it into the next variable, but seeing as the <= notation makes this program worse, I really just need a simple fix for the program thanks.
I think it's because you're not cleaning off the newline from 'string' when you've done it for the input line from the file. EG, you're doing this:
str[strlen(str)-1] = '\0';
But not this:
string[strlen(string)-1] = '\0';
(as a side note, you should avoid using the word 'string' in C-code just in case you ever want to port it to C++ in the future)
I think that you should correct this statement:
(!(text[c] == ' ' && text[c] == ' ')) to this:
(!((text[c] == ' ') && (text[c] == ' ')))
compiler may compile both, but wont work properly in your case
I'd like to be able to compare a character on stdin with a characters of my specification. The purpose of this is to filter out every other input as wrong, while maintaining only the specified single chars as commands. Like on stdin "nn" or "qddaw" -> wrong go again but "n" make something useful.
Here is what I have in mind "code-wise":
if (input does not contain 'c' or 's' or 'q' or 'n') {
printf("some kind of error");
}
Well I tried to create an array with specified characters like array[] = {'a', 'b', 'c'} so I could be able to compare it with a string on the stdin with function strncmp.. like
char c[256];
scanf("%s", c)
if (strncmp(array, c, 1) != 0) printf("error");
but it doesn't seem to work. Any suggestions?
Edit1: Here is actual piece of code:
char c[256];
char* s = "nsrld";
char* quiter = "q";
do
{
printf(">");
scanf("%s", c);
if (only when there is no 'n' or 's' or other char from char* s on input)
{
errorHandle(ERROR_WRONG_CMD);
}
scanf("%*[^\n]"); scanf("%*c");
} while (strcmp(c,quiter) != 0);
as you can see I handled the 'q' thing quite well, but multiple chars are pain in the ass. Thanks for any advice.
Edit 2: or in other words I need a function which will compare input with a set of given characters and only if there is one OR another (like 'q' or 's' the function will pass (but not if there are characters together like 'qs')
I didn't make myself clear enough. What I need is input "type what ever you want" like "wwqwqe" and do the error unless the input is just 'c' or just 's' (and a few more).
char usersInput[200] = ""; /* A buffer to hold the input values */
char *result = gets(usersInput); /* Fill the buffer from stdin */
if (result != NULL) /* If we got something */
{
if (strlen(usersInput) == 1) /* the input must be exactly 1 character */
{
char ch = usersInput[0];
if (strchr(ch, "csqn") == NULL) /* It must be a valid values */
{
printf("Evil Bad Character <%c>\n", ch);
}
else
{
/* Do stuff with the known valid input value ch */
}
}
else
{
puts("The input value must be exactly 1 character\n");
puts("and must be 'c', 's', 'q' or 'n'");
}
}
else
{
puts("EOF or ERROR while reading stdin\n");
}
This should do the job.
One warning. gets is not smart enough to know that usersInput is 200 characters long.
It will gleefully let you type in 201 characters or more, which overwrites other characters in memory. That sort of thing can lead to hard-to-find bugs.
int ch = getchar();
if (ch != EOF)
{
if (strchr("csqn", ch) == NULL)
{
printf("Evil Bad Character <%c> in Hex %02X\n", ch, ch);
}
else
{
/* Do stuff with ch */
}
}
else
{
printf("EOF on input\n");
}
char c = getchar();
switch (c) {
case 'c':
case 's':
case 'q':
case 'n':
do_something();
break;
default:
print_error();
};
The above code should work. I don't know why your if statement wasn't working. Generally a switch works well in this type of scenario too.
Your first solution should work. If that's the exact same code you posted - then your problem might because the printf needs a newline at the end to flush to console.
I have thought the string as sets... So if the intersection of them is the void set then we will fail -> printf("Error")... otherwise the output is none...
#include <stdio.h>
#include <string.h>
int intersection(char* source, char* search)
{
int i,j;
for(i = 0; i < strlen(search); i++)
if(strchr(source,search[i]))j++;
if(j != strlen(search))return 0;
else return 1;
}
int main()
{
char *letters = "eo";
char *p = "hello";
int e = intersection(p,letters);
if(e==1)puts("Non Void");
else puts("Void");
}
While it looks as if you've got a solution, it might be worth mentioning that what you're asking for doesn't sound as if it's all that far away from the standard 'getopt' functionality... See http://www.gnu.org/software/libc/manual/html_node/Getopt.html for example.
This worked for me:
char c[256];
char* s = "nqsrld";
char* quiter = "q";
do
{
printf(">");
scanf("%s", c);
if ((strpbrk(s, c) == 0) || (strlen(c) >= 2))
{
errorHandle(ERROR_WRONG_CMD);
}
scanf("%*[^\n]"); scanf("%*c");
} while (strcmp(c,quiter) != 0);
Thanks to everyone for their help.
Write a function
int IsGood(int c)
{
if(c=='a'||c=='b'||c=='c')
return 1;
else
return 0;
}
EDIT:
complete code with main is here http://codepad.org/79aLzj2H
and once again this is were the weird behavious is happening
for (i = 0; i<tab_size; i++)
{
//CORRECT OUTPUT
printf("%s\n", tableau[i].capitale);
printf("%s\n", tableau[i].pays);
printf("%s\n", tableau[i].commentaire);
//WRONG OUTPUT
//printf("%s --- %s --- %s |\n", tableau[i].capitale, tableau[i].pays, tableau[i].commentaire);
}
I have an array of the following strcuture
struct T_info
{
char capitale[255];
char pays[255];
char commentaire[255];
};
struct T_info *tableau;
This is how the array is populated
int advance(FILE *f)
{
char c;
c = getc(f);
if(c == '\n')
return 0;
while(c != EOF && (c == ' ' || c == '\t'))
{
c = getc(f);
}
return fseek(f, -1, SEEK_CUR);
}
int get_word(FILE *f, char * buffer)
{
char c;
int count = 0;
int space = 0;
while((c = getc(f)) != EOF)
{
if (c == '\n')
{
buffer[count] = '\0';
return -2;
}
if ((c == ' ' || c == '\t') && space < 1)
{
buffer[count] = c;
count ++;
space++;
}
else
{
if (c != ' ' && c != '\t')
{
buffer[count] = c;
count ++;
space = 0;
}
else /* more than one space*/
{
advance(f);
break;
}
}
}
buffer[count] = '\0';
if(c == EOF)
return -1;
return count;
}
void fill_table(FILE *f,struct T_info *tab)
{
int line = 0, column = 0;
fseek(f, 0, SEEK_SET);
char buffer[MAX_LINE];
char c;
int res;
int i = 0;
while((res = get_word(f, buffer)) != -999)
{
switch(column)
{
case 0:
strcpy(tab[line].capitale, buffer);
column++;
break;
case 1:
strcpy(tab[line].pays, buffer);
column++;
break;
default:
strcpy(tab[line].commentaire, buffer);
column++;
break;
}
/*if I printf each one alone here, everything works ok*/
//last word in line
if (res == -2)
{
if (column == 2)
{
strcpy(tab[line].commentaire, " ");
}
//wrong output here
printf("%s -- %s -- %s\n", tab[line].capitale, tab[line].pays, tab[line].commentaire);
column = 0;
line++;
continue;
}
column = column % 3;
if (column == 0)
{
line++;
}
/*EOF reached*/
if(res == -1)
return;
}
return ;
}
Edit :
trying this
printf("%s -- ", tab[line].capitale);
printf("%s --", tab[line].pays);
printf("%s --\n", tab[line].commentaire);
gives me as result
-- --abi -- Emirats arabes unis
I expect to get
Abu Dhabi -- Emirats arabes unis --
Am I missing something?
Does printf have side effects?
Well, it prints to the screen. That's a side effect. Other than that: no.
is printf changing its parameters
No
I get wrong resutts [...] what is going on?
If by wrong results you mean that the output does not appear when it should, this is probably just a line buffering issue (your second version does not print newline which may cause the output to not be flushed).
It's highly unlikely that printf is your problem. What is far, far more likely is that you're corrupting memory and your strange results from printf are just a symptom.
There are several places I see in your code which might result in reading or writing past the end of an array. It's hard to say which of them might be causing you problems without seeing your input, but here are a few that I noticed:
get_lines_count won't count the last line if it doesn't end in a newline, but your other methods will process that line
advance will skip over a newline if it is preceded by spaces, which will cause your column-based processing to get off, and could result in some of your strings being uninitialized
get_word doesn't do any bounds checks on buffer
There may be others, those were just the ones that popped out at me.
I tested your code, adding the missing parts (MAX_LINE constant, main function and a sample datafile with three columns separated by 2+ whitespace), and the code works as expected.
Perhaps the code you posted is still not complete (fill_table() looks for a -999 magic number from get_word(), but get_word() never returns that), your main function is missing, so we don't know if you are properly allocating memory, etc.
Unrelated but important: it is not recommended (and also not portable) to do relative movements with fseek in text files. You probably want to use ungetc instead in this case. If you really want to move the file pointer while reading a text stream, you should use fgetpos and fsetpos.
Your approach for getting help is very wrong. You assumed that printf had side effects without even understanding your code. The problem is clearly not in printf, but you held information unnecessarily. Your code is not complete. You should create a reduced testcase that compiles and displays your problem clearly, and include it in full in your question. Don't blame random library functions if you don't understand what is really wrong with your program. The problem can be anywhere.
From your comments, i am assuming if you use these printf statements,
printf("%s\n", tableau[i].capitale);
printf("%s", tableau[i].pays);
printf("%s\n", tableau[i].commentaire);
then everything works fine...
So try replacing your single printf statement with this. (Line no. 173 in http://codepad.org/79aLzj2H)
printf("%s\n %s %s /n", tableau[i].capitale, tableau[i].pays, tableau[i].commentaire);