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.
Related
Today I decided to learn to code for the first time in my life. I decided to learn C. I have created a small program that checks a txt file for a specific value. If it finds that value then it will tell you that that specific value has been found.
What I would like to do is that I can put multiple files go through this program. I want this program to be able to scan all files in a folder for a specific string and display what files contain that string (basically a file index)
I just started today and I'm 15 years old so I don't know if my assumptions are correct on how this can be done and I'm sorry if it may sound stupid but I have been thinking of maybe creating a thread for every directory I put into this program and each thread individually runs that code on the single file and then it displays all the directories in which the string can be found.
I have been looking into threading but I don't quite understand it. Here's the working code for one file at a time. Does anyone know how to make this work as I want it?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
//searches for this string in a txt file
char searchforthis[200];
//file name to display at output
char ch, file_name[200];
FILE *fp;
//Asks for full directory of txt file (example: C:\users\...) and reads that file.
//fp is content of file
printf("Enter name of a file you wish to check:\n");
gets(file_name);
fp = fopen(file_name, "r"); // read mode
//If there's no data inside the file it displays following error message
if (fp == NULL)
{
perror("Error while opening the file.\n");
exit(EXIT_FAILURE);
}
//asks for string (what has to be searched)
printf("Enter what you want to search: \n");
scanf("%s", searchforthis);
char* p;
// Find first occurrence of searchforthis in fp
p = strstr(searchforthis, fp);
// Prints the result
if (p) {
printf("This Value was found in following file:\n%s", file_name);
} else
printf("This Value has not been found.\n");
fclose(fp);
return 0;
}
This line,
p = strstr(searchforthis, fp);
is wrong. strstr() is defined as, char *strstr(const char *haystack, const char *needle), no file pointers in it.
Forget about gets(), its prone to overflow, reference, Why is the gets function so dangerous that it should not be used?.
Your scanf("%s",...) is equally dangerous to using gets() as you don't limit the character to be read. Instead, you could re-format it as,
scanf("%199s", searchforthis); /* 199 characters + \0 to mark the end of the string */
Also check the return value of scanf() , in case an input error occurs, final code should look like this,
if (scanf("%199s", searchforthis) != 1)
{
exit(EXIT_FAILURE);
}
It is even better, if you use fgets() for this, though keep in mind that fgets() will also save the newline character in the buffer, you are going to have to strip it manually.
To actually perform checks on the file, you have to read the file line by line, by using a function like, fgets() or fscanf(), or POSIX getline() and then use strstr() on each line to determine if you have a match or not, something like this should work,
char *p;
char buff[500];
int flag = 0, lines = 1;
while (fgets(buff, sizeof(buff), fp) != NULL)
{
size_t len = strlen(buff); /* get the length of the string */
if (len > 0 && buff[len - 1] == '\n') /* check if the last character is the newline character */
{
buff[len - 1] = '\0'; /* place \0 in the place of \n */
}
p = strstr(buff, searchforthis);
if (p != NULL)
{
/* match - set flag to 1 */
flag = 1;
break;
}
}
if (flag == 0)
{
printf("This Value has not been found.\n");
}
else
{
printf("This Value was found in following file:\n%s", file_name);
}
flag is used to determine whether or not searchforthis exists in the file.
Side note, if the line contains more than 499 characters, you will need a larger buffer, or a different function, consider getline() for that case, or even a custom one reading character by character.
If you want to do this for multiple files, you have to place the whole process in a loop. For example,
for (int i = 0; i < 5; i++) /* this will execute 5 times */
{
printf("Enter name of a file you wish to check:\n");
...
}
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.
I am trying to write a simple C program that loads a text-file, prints the first line to screen, waits for the user to press enter and then prints the next line, and so on.
As only argument it accepts a text-file that is loaded as a stream "database". I use the getline()-function for this, according to this example. It compiles fine, successfully loads the text-file, but the program never enters the while-loop and then exits.
#include <stdio.h>
#include <stdlib.h>
FILE *database = NULL; // input file
int main(int argc, char *argv[])
{
/* assuming the user obeyed syntax and gave input-file as first argument*/
char *input = argv[1];
/* Initializing input/database file */
database = fopen(input, "r");
if(database == NULL)
{
fprintf(stderr, "Something went wrong with reading the database/input file. Does it exist?\n");
exit(EXIT_FAILURE);
}
printf("INFO: database file %s loaded.\n", input);
/* Crucial part printing line after line */
char *line = NULL;
size_t len = 0;
ssize_t read;
while((read = getline(&line, &len, database)) != -1)
{
printf("INFO: Retrieved line of length %zu :\n", read);
printf("%s \n", line);
char confirm; // wait for user keystroke to proceed
scanf("%c", &confirm);
// no need to do anything with "confirm"
}
/* tidy up */
free(line);
fclose(database);
exit(EXIT_SUCCESS);
}
I tried it with fgets() -- I can also post that code --, but same thing there: it never enters the while-loop.
It might be something very obvious; I am new to programming.
I use the gcc-compiler on Kali Linux.
Change your scanf with fgetline using stdin as your file parameter.
You should step through this in a debugger, to make sure your claim that it never enters the while loop is correct.
If it truly never enters the while loop, it is necessarily because getline() has returned -1. Either the file is truly empty, or you have an error reading the file.
man getline says:
On success, getline() and getdelim() return the number of
characters
read, including the delimiter character, but not including the termiā
nating null byte ('\0'). This value can be used to handle embedded
null bytes in the line read.
Both functions return -1 on failure to read a line (including end-of-
file condition). In the event of an error, errno is set to indicate
the cause.
Therefore, you should enhance your code to check for stream errors and deal with errno -- you should do this even when your code works, because EOF is not the only reason for the function
to return -1.
int len = getline(&line, &len, database);
if(len == -1 && ferror(database)) {
perror("Error reading database");
}
You can write more detailed code to deal with errno in more explicit ways.
Unfortunately handling this thoroughly can make your code a bit more verbose -- welcome to C!
A friend of mine needs to use MATLAB for one of his classes, so he called me up (a Computer Science Major) and asked if I could teach him C. I am familiar with C++, so I am also familiar with the general syntax, but had to read up on the IO library for C.
I was creating some simple IO programs to show my friend, but my third program is causing me trouble. When I run the program on my machine using Eclipse (with the CDT) Eclipse's console produces a glitchy output where instead of prompting me for the data, it gets the input and then prints it all at once with FAILURE.
The program is supposed to get a filename from user, create the file, and write to it until the user enters a blank line.
When I compile/run it on my machine via console (g++ files2.c) I am prompted for the data properly, but FAILURE shows up, and there is no output file.
I think the error lies with how I am using the char arrays, since using scanf to get the filename will create a functional file (probably since it ignores whitespace), but not enter the while loop.
#include <stdio.h>
#define name_length 20
#define line_size 80
int main() {
FILE * write_file; // pointer to file you will write to
char filename[name_length]; // variable to hold the name of file
char string_buffer[line_size]; // buffer to hold your text
printf("Filename: "); // prompt for filename
fgets(filename, name_length, stdin); // get filename from user
if (filename[name_length-1] == '\n') // if last char in stream is newline,
{filename[name_length-1] = '\0';} // remove it
write_file = fopen(filename, "w"); // create/overwrite file user named
if (!write_file) {printf("FAILURE");} // failed to create FILE *
// inform user how to exit
printf("To exit, enter a blank line (no spaces)\n");
// while getting input, print to file
while (fgets(string_buffer, line_size, stdin) != NULL) {
fputs(string_buffer, write_file);
if (string_buffer[0] == '\n') {break;}
}
fclose(write_file);
return 0;
}
How should I go about fixing the program? I have found next to nothing on user-terminated input being written to file.
Now if you will excuse me, I have a couple of files to delete off of my University's UNIX server, and I cannot specify them by name since they were created with convoluted filenames...
EDIT------
Like I said, I was able to use
scanf("%s", filename);
to get a working filename (without the newline char). But regardless of if I use scanf or fgets for my while loop, if I use them in conjunction with scanf for the filename, I am not able to write anything to file, as it does not enter the while loop.
How should I restructure my writing to file and my while loop?
Your check for the newline is wrong; you're looking at the last character in filename but it may be before that if the user enters a filename that's shorter than the maximum. You're then trying to open a file that has a newline in it's name.
These lines seem to be incorrect:
if (filename[name_length-1] == '\n') // if last char in stream is newline,
{filename[name_length-1] = '\0';} // remove it
You verify the name_length - 1 character,, which is 19 in your case without any regard of the introduced filename's length. So if your file name's length is less then 18 you won't replace the '\n' character at the end of your string. Obviously the file name can't contain '\n' character.
You need to get the size of you file name first with strlen() as an example.
if (filename[strlen(filename) - 1] == '\n')
{
filename[strlen(filename) - 1] = '\0';
}
(Don't forget to include the string.h header)
I hope I was able to help with my weak english.
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