char filePath[200];
printf("Enter filepath: \n");
fgets(filePath, 200, stdin);
f = fopen(filePath, "r");
while(!feof(f)) // crashed on this line
{
}
I cannot for some reason get this to work.
Please could some one point out what I am doing wrong on this.
Could you advice the correct way to write code for opening a filepath specified by user through command prompt?
Thanks,
Freddy
fopen(3) returns NULL if it cannot open the file. You should always check for that. fgets(3) does that too, but your problem is probably the new-line character that it keeps in the returned string.
fgets puts endline to the end of string (\r\n in Windows). So your filePath contains garbage at the end and file of that name doesn't exist. I would recommend to use scanf("%[^\r\n]s", filePath) instead. (scanf may differ on some implementations, please read your documentation.)
update: You should also ensure there won't be a buffer overflow by specifying buffer size. For example this way:
char filePath[100];
scanf("%99[^\r\n]s", filePath);
Try something like:
size_t l = strlen(filePath);
if (filePath[l-1] == '\n') filePath[--l-1] = 0;
if (filePath[l-1] == '\r') filePath[--l-1] = 0;
You check the error code from fgets and fopen. Both return null if they failed
Related
This is the code.
FILE* fPtr;
FILE* fTemp;
char path[100];
char buffer[BUFFER_SIZE];
char newline[BUFFER_SIZE];
int line, count;
printf("Enter path of source file: ");
scanf("%s", path);
printf("Enter line number to replace: ");
scanf("%d", &line);
/* Remove extra new line character from stdin */
fflush(stdin);
printf("Replace '%d' line with: ", line);
scanf("%s", &newline);
/* Open all required files */
fPtr = fopen(path, "r");
fTemp = fopen("replace.tmp", "w");
/* fopen() return NULL if unable to open file in given mode. */
if (!fPtr)
{
/* Unable to open file hence exit */
printf("\nUnable to open file.\n");
printf("Please check whether file exists and you have read/write privilege.\n");
exit(EXIT_SUCCESS);
}
/*
* Read line from source file and write to destination
* file after replacing given line.
*/
count = 0;
while ((fgets(buffer, BUFFER_SIZE, fPtr)) != 0)
{
count++;
/* If current line is line to replace */
if (count == line)
fputs(newline, fTemp);
else
fputs(buffer, fTemp);
}
/* Close all files to release resource */
fclose(fPtr);
fclose(fTemp);
/* Delete original source file */
remove(path);
/* Rename temporary file as original file */
rename("replace.tmp", path);
printf("\nSuccessfully replaced '%d' line with '%s'.", line, newline);
return 0;
I wanted to replace a line supposedly the content of the text file is this
> Andy,06/05/2000,US,0654852,254845,313132
> Fan,865644,4654654,654654,465456
> Ben,04/01/1995,SG,0674874,213454,132158
Supposedly I wanted to change the of Fan so I run the code above, it gave me this. I do not want this to happen.
> Andy,06/05/2000,US,0654852,254845,313132
> Fanny,865644,4654654,654654,465456Ben,04/01/1995,SG,0674874,213454,132158
And if I want to change the name of Andy it gave me this
Landy,06/05/2000,US,0654852,254845,313132Fanny,865644,4654654,654654,465456Ben,04/01/1995,SG,0674874,213454,13215
Why it does that?
How do I delete specific line and replace it ?
Assume that the replacement line has a different size than the original one. You cannot do that in standard C11 (check n1570) without copying the file to a new place (because you cannot overwrite a sequence of bytes in the middle of a file by another sequence of different length).
Read carefully the documentation of <stdio.h>
Lines are just a convention in C: they are ending by some end-of-line character (\n). A file could have a single line and contain a megabyte.
So you could use getline to read lines. Or use fgets. In both cases you should check for failure. With fgets what would happen if the line is bigger than the buffer? With getline what would happen with a file containing a single line of a gigabyte which does not fit into memory?
Be aware that stdout is buffered (and the buffer size could vary from one run to the next one and could be different if you use command pipelines). See setvbuf and fflush. In practice, take the habit of ending your printf format control string with \n and/or explicitly calling fflush
Many open source programs doing what you want already exist. GNU ed comes to mind. Consider studying its source code for inspiration.
Please read how to debug small programs. If you use a recent GCC compiler with some GDB debugger, compile with all warnings and debug info, so gcc -Wall -Wextra -g then use gdb to understand the behavior of your program. Specify on paper the input file syntax using EBNF and read more about parsing techniques, including recursive descent parsing.
Notice that:
fflush(stdin);
is undefined behavior. You should fflush output streams only.
PS. You could later read about databases then consider using sqlite.
fgets will read from the file up to and including the newline character at the end of the line. The scanf call you use to get the replacement string does not, so when you write out newline it does not contain a newline character.
Solutions include explicitly adding the newline (possibly with fputc('\n', fTemp);, or using fgets(newline, BUFFER_SIZE, stdin); instead of the scanf to read your input string.
Yes I want to use
fgets(new,line,buffer_sizze,stdin);
but it just won't ask for input unless I put it inside of main().
When I put it inside of a function that I created, it won't ask for input from the user which is why I used scanf.
Is there a way to put it \n without asking the user to type \n.
Or any solution to why it's not getting input when I used fgets.
For the people that has the same problem as me.
Fgets not asking for any input.
Try use getchar().
That solved my problem.
For unknown reason.
Here's the file I want to read.
single
splash
single
V-Line
h-line
Macro for checking if string is equal.
#define STR_MATCH(a,b) (strncmp((a),(b),strlen(b)+1) == 0)
Here's what i'm using to read it.
void readMissilesFile(char* fileName)
{
FILE* mFile;
char missile[7];
/* Open the file. */
mFile = fopen(fileName, "r");
if (mFile != NULL)
{
while (!feof(mFile))
{
fgets(missile, 7, mFile);
if (!(STR_MATCH(missile, "\n")))
{
printf("Missile: %s", missile);
}
}
fclose(mFile);
}
else
{
perror("Could not open the file.");
}
}
So i'm having difficulties as its printing out spaces when I read the line. I tried to ignore this by ensuring it only reads 7 characters which is the max length of each missile. Then I made a macro called strcmp which just checks if they are equal(to hopefully not print it).
Please find the macro attached as well.
Thanks in advance and any help is great. :)
If I understand your question correctly you can replace the newline characters by using strcspn.
You should not use feof like this, this post explains why. A safe way to read the file till the end is to use fgets as stop condition in the while loop.
The container, missile should be one char bigger than the max size of the largest string to accomodate for '\0'.
Live sample
#include <string.h>
//...
char missile[10];
//...
if (mFile != NULL)
{
while (fgets(missile, 10, mFile)) //will read till there are no more lines
{
missile[strcspn(missile, "\r\n")] = '\0'; //remove newline characters
printf("Missile: %s ", missile);
}
}
//...
I would advise the reading of this post which has detailed info about fgets, namely the issue of newline characters consumption.
There is getline function in stdio.h which reads line until delimiter. Its a POSIX though, so if you are on Windows you may lack it.
Here is example implementation:
https://github.com/ivanrad/getline/blob/master/getline.c
It may be a stupid issue but its been a few hours I've been looking around to fix that and it drives me crazy.
That little code works perfectly fine if the fgets line is commentated (as provided).
As soon as I remove the comment the whole function will NOT do anything at all. My process jut freezes - even the printf before the fgets isnt executed.
void RetirerTransaction(char* filePath, char* transaction) {
FILE* f;
FILE* result;
char tempStr[128];
char line[100];
printf(">>%s<<",filePath); // Just to check everything is ok
strcpy(tempStr,"grep -v \"");
strcat(tempStr,transaction);
strcat(tempStr,"\"");
strcat(tempStr,filePath); // tempStr = grep -v "XXX" myfile
result = popen(tempStr, "r");
/*
if (fgets(line,100,result)) {
printf("OK");
}
*/
}
Thank you in advance.
You miss a space between the closing quote of the pattern and the file parameter for grep. That makes the whole thing including the filename be taken as the pattern.
By default, grep reads from standard input. It blocks trying to read from stdin because it doesn't have a file parameter.
Add the space like this and you'll be fine:
strcat(tempStr,"\" ");
Check the code below.Please add check for the popen return value. If popen fails and you are trying to do a fgets() then it might cause crash.
result = popen(tempStr, "r");
if(result == NULL)
return;
else
fgets(line,100,result);
I searched the forum, and can't find the answer to this problem. It seems to be common, but none of the mentioned fixes are applicable.
This is my code for opening a file:
#include <stdio.h>
#include <string.h>
void main() {
FILE *input;
char path[200];
printf("Enter the full file path and file name in the following format:"
"\nC:\\Users\\Username\\etc......\\filename.extension\n");
fgets(path, 200, stdin);
printf("%s",path);
input=fopen(path,"r");
if (input==NULL) {
perror("The following errors were encountered");
return(-1);
}
}
printf(%s,path) correctly displays the path and name of the file I want to open, but fopen always returns invalid argument. I have also tried using a pointer to path in fopen, but this always crashes the program.
You are getting path with fgets. \n is considered a valid character by fgets. You need to remove it manually.
fgets(path, 200, stdin);
path[strlen(path) - 1] = '\0';
Your problem is probably that fgets does not remove the trailing '\n' from the input line before returning it. fopen cheerfully tries to open a file whose name contains '\n', but (assuming, as your code suggests, that you are using Windows) the operating system does not allow file names to contain that character, which is why you are getting an "Invalid argument" message. On a Unix-type system, where the kernel imposes far fewer constraints on file names, you would have instead gotten "No such file or directory". This may be why you didn't find any previous answers to this question; I know I've seen variations before.
Try this:
...
fgets(path, 200, stdin);
char *p = path + strlen(path) - 1;
while (isspace(*p)) p--;
*(p+1) = '\0';
printf("%s\n", path);
input = fopen(path, "r");
...
You will need #include <ctype.h> for isspace.
I don't know exactly why a file pointer reads an extra line from a file, specifically the last line, here is the code:
FILE *fp ;
fp = fopen ("mac_ip.txt", "r") ;
int mac;
char *ip = (char *) malloc(15);
while(!feof(fp)){
fscanf(fp,"%i",&mac);
fscanf(fp,"%s",ip);
printf("MAC: %i\n",mac);
printf("IP: %s\n",ip);
}
and the file has exactly 20 lines, but the line 20, is printed twice.
Which is the error?
Thanks in advance.
Because after reading the last two values, you still haven't hit EOF. So the loop goes on. In the next pass of the loop, fscanf actually does not read the last line for the second time like it appears, the fscanfs fail, but the printfs print out the values from the previous pass of the loop.
feof does not "know" it's at the end of file until you try to read some more. Since fscanf tells you how many items it got, you can use this simple trick:
for(;;){
if (fscanf(fp,"%i%s", &mac, ip) != 2) break;
printf("MAC: %i\n",mac);
printf("IP: %s\n",ip);
}
After you have done the two reads on the twentieth line, you have got to the end of the file but the system doesn't know this. feof will only trigger when you try to get past the end of the file, not when you are exactly on it ...
Also, you may have a line-end (CR or CR-LF) on the 20th line which it will only get past with another attempted read.
The solution is to read the line in one go (there is a specific C command for this) and then parse that to get your data. If the whole-line read fails, then you've got to the end.
Your code resembles to the following example
#include <stdio.h>
int main(void)
{
char buffer[256];
FILE * myfile;
myfile = fopen("some.txt","r");
while (!feof(myfile))
{
fgets(buffer,256,myfile);
printf("%s",buffer);
}
fclose(myfile);
return 0;
}
from
http://www.friedspace.com/feof.html
You better test for fscanf return value before printing result. I bet that in the last iteration of your loop, fscanf calls fail and you print the last returned results.
FILE *fp ;
int mac;
char ip[15];
fp = fopen ("mac_ip.txt", "r") ;
if (!fp) return;
while(1){
if (fscanf(fp,"%i",&mac) < 1) break;
if (fscanf(fp,"%s",ip) < 1) break;
printf("MAC: %i\n",mac);
printf("IP: %s\n",ip);
}
fclose (fp);
fscanf() returns the number of assignments it mad (or -1 on eof). By using the return value, you don't need the eof() function. BTW I don't think you can read a MAC address into an int. Maybe you need to read that into a string, too ?
Explanation: feof() does not do what the OP expects. feof() should only be inspected after one of the file operations failed. In most cases you don't need feof().