C: File loop not reading right [duplicate] - c

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

Related

Char array being cleared after unrelated function call to fgets?

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

I am trying to delete a word from a file in C

I wrote a program to remove a certain word (taken as user input) from a file. I read the word, opened the file from which I wanted to delete the word, read each line in the file and split it into words, and compared each word with my keyword. If they are not a match, I printed them into a temporary file.
But when I open the temp file, the entire text has been copied. Can somebody help me????
#include<stdio.h>
#include<fcntl.h>
#include<string.h>
main()
{
int i;
FILE *fp1,*fp2;
char key[1000],a[1000],temp[1000];
printf("\nEnter the word to be deleted from file : ");
scanf("%s",key);
fp1 = fopen("a.txt","r");
fp2 = fopen("b.txt","w");
while(fgets(a,1000,fp1))
{
for(i=0;a[i]!='\0';++i)
if(a[i]==' ')
break;
else
temp[i]=a[i];
temp[i]='\0';
if(strcmp(temp,key)!=0)
{
fputs(temp,fp2);
}
bzero(a,1000);
}
fclose(fp1);
fclose(fp2);
printf("\n\n");
/*remove("a.txt");
rename("b.txt","a.txt");*/
}
Yet another solution. It has some of the same problems mentioned above, for example the boundaries of a word do not really match English grammar. It also has an inefficiency of doing more copies than is strictly necessary in some cases.
However, I prefer this version over yours because it abstracts the word removal task rather than doing it inline with the rest of the code. Plus it works better.
#include <stdio.h>
#include <string.h>
void remove_str2(char* buffer, char* find, int lfind) {
char* paste = strstr(buffer, find);
if (!paste) { return; }
char* start = paste + lfind;
while (1) {
char* end = strstr(start, find);
if (!end) {
end = start + strlen(start) + 1;
}
memmove(paste, start, end - start);
paste += end - start;
start = strstr(end, find);
if (!start) { return; }
start += lfind;
}
}
void remove_str(char* buffer, char* find, int lfind) {
char* p = strstr(buffer, find);
if (p) {
remove_str(p + lfind, find, lfind);
// shift everything left
do { *p = *(p + lfind); } while (*(++p));
}
}
int main() {
FILE *fp1, *fp2;
char key[1000], a[1000];
// require key to be preceeded by a space
key[0] = ' ';
printf("\nEnter the word to be deleted from file : ");
scanf("%s", &key[1]);
fp1 = fopen("a.txt","r");
fp2 = fopen("b.txt","w");
while (fgets(a, 1000, fp1)) {
remove_str(a, key, strlen(key));
fputs(a, fp2);
}
fclose(fp1);
fclose(fp2);
printf("\n\n");
return 0;
}
Tried to compile it and it works almost fine except it doesn't insert spaces in output file ;)
if(strcmp(temp,key)!=0)
{
temp[i++] = ' ';
temp[i] = '\0';
fputs(temp,fp2);
}
Also, its' very sensitive code. It doesn't work if I have a line of words. And it shouldn't work if your test file has a spaces before word and your keyword doesn't.
Some observations,
main()
{
//you will need input index, output index
int in, on; //in: input index, on: output index
FILE *fp1,*fp2;
char key[1000],iray[1000],oray[1000];
char* here; //clarifies the comparison
printf("\nEnter the word to be deleted from file : ");
scanf("%s",key);
printf("key: %s",key); fflush(stdout);
if(!(fp1 = fopen("a.txt","r"))) { printf("open error\n"); exit(1); }
if(!(fp2 = fopen("b.txt","w"))) { printf("open error\n"); exit(2); }
while(fgets(iray,sizeof(iray),fp1))
{
printf("line: %s",iray); fflush(stdout);
for(in=on=0; iray[in]; ++in) //'\0' = 0 = false //please indent
{ //please use braces
//printf("%d: %c\n",in,iray[in]); fflush(stdout);
if(iray[in]==' ')
{
oray[on++] = iray[in];
continue; //break gets you out of loop
}
here = &(iray[in]);
//printf("here: %s\n",here); fflush(stdout);
if( !strcmp(here,key) ) //have word?
{
in+=strlen(key); //skip word
continue;
}
oray[on++] = iray[in];
}
oray[on] = '\0';
printf("line: %s",oray); fflush(stdout);
fputs(oray,fp2);
iray[0]=0; //bzero(iray,1000);
oray[0]=0; //bzero(oray,1000);
}
fclose(fp1);
}
Part of the problem is that as soon as you find a space you process the word, but you don't finish processing the remainder of the line. After the fputs, you go to the top of the loop and read another line. When I compile and run your snippet, it indeed ouputs the first word of each line as long as it's not the selected word.
Also when outputting your words, you don't output any space between them and there is no carriage return at the end of lines. Thus all non-matching words are output back-to-back on one line.
There's a few more issues that the following snippet fixes (there's some remaining problems that I didn't solve-- for example, the last non-matching word on a line is not output if there is no trailing space on the line. You can solve this by looking for '\0' as well as space. I didn't do it because it requires changing the loop structure to not exit when '\0' is seen so you get a chance to test for it):
while(fgets(a,1000,fp1))
{
int j = 0;
for(i=0;a[i]!='\0';++i)
if((a[i]==' '){
temp[j++]='\0';
if(strcmp(temp,key)!=0) {
fprintf (fp2, "%s ", temp);
}
j = 0;
}
else
temp[j++]=a[i];
fprintf (fp2, "\n");
}
EDIT: a complete solution:
this is how your loop should look like:
while(fgets(a,1000,fp1))
{
int j=0;
for(i=0;a[i]!='\0';++i)
{
if(a[i]==' ')
{
temp[j]=0;
if(strcmp(temp,key)!=0)
{
fputs(temp,fp2);
}
j=0;
//this should be after fputs if you want to remove the space after obsolete word.
fputs(" ",fp2);
}
else
temp[j++]=a[i];
}
//last word if there is no space after!
if(strcmp(temp,key)!=0)
{
fputs(temp,fp2);
}
fputs("\n",fp2);
a[0] = 0;
}

C Program that counts Words and Lines in Standard input

I am new to C programming and I am currently trying to teach myself how to create a C program that can count words and lines in the input stream and print the two totals to the standard output.
What I am actually trying to do is to have the program count the number of lines and count the number of words depending on the definition of a word in which I feel that I am off.
I want the words to exclude blanks, tabs, newlines, hyphens, or colons. While having the program output the results (words and lines) as decimals.
#include<stdio.h>
int main()
{
int iochar;
int words;
int lines;
printf("Enter something here:\n\n");
while ((iochar = getchar ()) !=EOF)
{
if((iochar == ' ') || (iochar == '\t') || (iochar == '\n'))
putchar(iochar);
}
return 0;
}
Am I totally off on this program?
If your question is how to fix the compile error, that's simple. Add one more closing brace at the end.
But your program will still do only one pass through the loop and will print only one character if and only if the user types a space, tab or newline. No matter what the user types, the program will then terminate. I doubt that's what you wanted.
I suspect this is what you intended:
while ((iochar = getchar ()) !=EOF)
{
if((iochar == ' ') || (iochar == '\t') || (iochar == '\n'))
{
putchar(iochar);
}
}
return 0;
After your "I am trying to have thee numbers be right justified in an 8-column field ..." I cannot understand what you are trying to say :(
int words = 0;
int lines = 0;
char buffer[1024];
while(fgets(buffer, sizeof buffer, stdin))
{
lines++;
if(buffer[0] == '\n')
continue;
char *tmp = buffer-1;
while(tmp = strchr(tmp+1, ' '))
words++;
words++; /* count last word before \0*/
}
printf("lines: %d, words: %d\n", lines, words);
is that what you need/want?
The error message is:
Test.c:20:1: error: expected declaration or statement at end of input
It does not compile because you are missing a }.
Had you properly indented your code, like so, you would have found your mistake:
#include<stdio.h>
int main() {
int iochar;
int words;
int lines;
printf("Enter something here:\n\n");
while ((iochar = getchar ()) !=EOF)
{
if((iochar==' ')||(iochar=='\t')||(iochar=='\n'))
{
putchar(iochar);
iochar = getchar();
}
return 0;
}
Yet another example of the importance of readability :)

how to parse plaintext from file into a 2d matrix/array?

the following code that I wrote is supposed to transform a line taken from a file like the following:
(3670, 1882) (1574, 7255) (4814, 8566) (1609, 3153) (9725, 13468) (8297, 3006) (9091, 6989) (8521, 10432) (14669, 12201) (4203, 9729) (469, 2444) (10107, 8318) (1848, 13650) (5423, 847) (11755, 8827) (4451, 4495) (11645, 1670) (10937, 5692) (14533, 13696) (7291, 12158) (1891, 2405) (1776, 4971) (2486, 2499) (13389, 236) (8533, 7531) (10618, 10288) (9119, 11226) (9429, 6622) (12380, 9516) (1698, 5828) (8369, 5101) (11341, 13530) (11955, 2335) (6249, 14435) (9373, 6921) (2977, 2294) (57, 14558) (280, 12847) (13846, 11748) (428, 9004)
into a valid 2d matrix.
{{3670, 1882},{1547, 7255}...}
I'm a good "pythoner" and I'd be able to do that in one line. I wanted to try to solve the same problem in c (note that I started to mess around with c today); my attempt is the following (and the result is quite random/wrong):
FILE *fp;
fp=fopen(argv[1], "rt");
if ( fp != NULL )
{
char line [1000]; //this is ugly, isn't this?
while ( fgets ( line, sizeof line, fp ) != NULL ) // read a line
{
line[(strlen(line)-1)] = '\0';
//line[(strlen(line)-2)] = '\0';
char* p;
p = strtok(line, ",)( ");
int elements[100][2]; //even uglier than before?
int binpos=0;
int pos=0;
while (p != NULL)
{
if (p!=NULL){
if (binpos==0){
elements[pos][binpos]=atoi(p);
binpos=1;
}else{
p[(strlen(p)-1)] = '\0'; //remove the comma
elements[pos][binpos]=atoi(p);
pos++;
binpos=0;
}
}
p = strtok(NULL, ",)( ");
}
int it;
for (it=0; it<pos; it++){
printf("(%d, %d)\n",elements[it][0],elements[it][1]);
}
return 0;
}
}
Can someone please tell me how to correct my mess? :)
You should only be using fgets to read lines if lines are relevant to what you are parsing. In your case it looks like line endings are irrelevant, so you're better off just using scanf:
printf("{");
const char *sep = "";
int a, b;
while (fscanf(fp, "(%d,%d)", &a, &b) == 2) {
printf("%s{%d, %d}", sep, a, b);
sep = ", "; }
printf("}");

Can printf change its parameters?

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

Resources