I came across a confused problem when I program in C
when i use oldPacket.filename = "fallout.jpg" //i have a file called fallout.jpg,and a struct called oldPakcet with an char* type filename
The program ran very well
Now, I decide to let user to in put the filename and also check the existence of the file. I wrote the following function:
bool Searchfile(packet* ptr) {
char userinput[100];
fgets(userinput, sizeof (userinput), stdin); //non terminated input by fgets
userinput[strcspn(userinput, "\n")] = 0;
//printf("%d\n",strlen(userinput));
ptr->filename = userinput + 4;//i skip the first 4 char since the correnct format is ftp <filename>
printf("%s\n",ptr->filename);
printf("%d\n",strlen(ptr->filename));
ptr->filename[strlen(ptr->filename)] = '\0';
if (access(ptr->filename, F_OK) != -1) {
printf("exist\n");
return false;
} else {
//printf("does not exist\n");
return true;
}
}
I call this function by
while (Searchfile(&oldPacket)){
printf("Please input the file name in the format: ftp <file name> \n");
}
However the program is no longer working and it shows seg fault at
int filesize;
fp = fopen(oldPacket.filename, "rb");
fseek(fp, 0L, SEEK_END);//here is the seg fault
Anyone have some idea why this happen ?
I already printf each char of the filename and it looks correct....
Thanks in advance
You let ptr->filename point to an address of local variable userinput, and accessing this value once userinput has gone out of scope is undefined behaviour.
The reason for the segfault is probably that the value of filename, when accessed outside of Searchfile, may be garbage, such that the file will not be opened. The subsequent fseek will then be called with a NULL-value for fp...
A simple solution to overcome this would be to write static char userinput[100];, at least when you are not working in a multithreaded environment. Otherwise you'd have to reserve memory for ptr->filename and copy contents of userinput.
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");
...
}
My program it's pretty big, so I'll highlight the main problem and add some details about it.
First part of my code:
int myPipe[2]; //A global variable, so I don't have to pass it to future functions
int main(int argc, char *args[])
{
mode_t pUmask = umask(0000); //Obsolete variable to my problem
errno = 0; //Obsolete variable to my problem
char pattern[2500] = "Test1"; //Obsolete variable to my problem
int p = 0; //DEFAULT NUMBER OF PROCESSES
int deep = 0; //Obsolete variable to my problem
int n = 1; //Obsolete variable to my problem
if(pipe(myPipe))
{
perror("Pipe Error: ");
exit(-1);
}
if( (write(myPipe[1], &p, (sizeof(int)*3))) == -1) //First write works
{
perror("write: ");
exit(-1);
}
//Then a bunch of code releated to file reading
}
Second part:
{
//in another function
//The part where I create fileName
char* fileName = calloc(strlen(fileData->d_name)+4, sizeof(char));
strcpy(fileName, fileData->d_name);
}
Third part:
//in another another function
if(S_ISREG(data.st_mode))
{
printf("\tfileName: %s\n", fileName); //Regular print of the right fileName
printf("\t\tOh boy! It's a regular.\n");
printf("\tfileName: %s\n", fileName); //Regular print of the right fileName
if((read(myPipe[0], &p, (sizeof(int)*3))) == -1) //First time I read
{
perror("\t\t read: ");
exit(-1);
}
printf("fileName: %s", fileName); //SEGMENTATION FAULT
There is a bunch of code in between, but it doesn't affect the fileName at all (in fact, up until the "read", fileName was printed flawlessly), and after it a SEGMENTATION FAULT happens.
At one point by changing the printfs locations I was able to get the fileName AFTER the read, which was basically the fileName value("File1") followed by the p integer value(0), which created the new corrupted fileName("File10").
So what's happening? I reserved the space for fileName, I passed the fileName pointer to the following functions up to that read, and supposedly the fd should have it's own adress space as well. HELP.
P.s. if you need more info, I'm willing to give it to you, even the full code, but it's REALLY complicated, and I think I gave you enough proof that fileName doesn't get corrupted at all until the read part, THANK YOU.
P.p.s.
I never close either of the "MyPipe" extremes, since I have to use them multiple times, I wanted to close them at the end of the program.
The statements that write and read the pipe are causing undefined behavior. p is declared:
int p;
But when you write and read it through the pipe, you use sizeof(int)*3, so you're accessing outside the object.
Change those statements to use just sizeof p.
I'm trying to have the program check, that, if a user inputs nothing the print statement will say it cant find the file name, but the issue I'm having is that the command line will just go to a new line after hitting enter instead of saying the print statement.
This is the code here. I was told that Null is the place holder for if nothing is put in so I thought it would work.
int main()
{
FILE *fin;
FILE *fout;
char fInName[50];
char fOutName[50];
printf("pleas type input file, and output file please type legibly\n ");
scanf("%s %s", &fInName, &fOutName);
fin = fopen(fInName, "r");
fout = fopen(fOutName, "r");
if (fInName == NULL && fOutName == NULL)
{
printf("Error: Cannot open input file %s.", fInName);
}
else if (fInName != NULL && fOutName == NULL)
{
printf("file found");
}
}
What im trying to test is if a first file name is entered and the second isnt then print the statement. If both arent entered then print file does not exist.
there is more to the code to see if the file exists or not, but thst would be a bit much, now Im just trying to understand why it wont read unentered data.
Ive tried looking at examples such as: How to detect empty string from fgets
and tried to alter the code to fit that type of style but it didnt work for me so Im giving you the code it was originally so that anything helpful wouldnt confuse me more.
Edit:
okay so I tried to do a simple code in order to see what may be the cause of this issue:
int main()
{
char firstname[50];
char lastname[50];
char nothing [0];
printf("pleas type input file, and output file please type legibly pwease\n ");
scanf("%s" "%s", firstname, lastname);
if (firstname == lastname )
{
printf("Error: Cannot open input file %s.", firstname);
}
else
{
printf("file found");
}
}
I ran the code using adam and either if I typed adam (space) adam or adam(enter) adam the program thinks that the input is not the same, I feel like that would help identify why it doesnt know why nothing is typed in.
The problem is occurring when you try to check if fInName == NULL.
The problem is that fInName is just a variable that you're using to store the name of the file that you want to open. What you actually want to check is that the user gave you a valid filename, and to do so you will want to understand what the return value of functions are.
For example, when you try to open a file using fopen(), if fopen() is unable to successfully open the file, say because the user didn't input anything or misspelled the filename, then fopen() will return NULL, storing it in whatever variable you assigned it to (in your case, *fin and *fout).
Also, scanf() is not recommended for char arrays because if the user inputs more data than you allocated for the array, which in this case is enough space for 50 characters, then scanf() will try to write data to memory that's not yours, causing a buffer overflow.
A much safer option is to use fgets() because you can choose exactly how much data is written into your char array, with the only downside being that fgets() will write newline characters \n (caused by hitting the enter key) into the array, though the simple solution is to overwrite the newline character with '\0'.
Therefore, I would propose:
int main(void)
{
char fInName[50];
char fOutName[50];
// ensure proper usage
do
{
printf("What file would you like to open? ");
// get infile from user and remove trailing newline '\n' character
fgets(fInName, 50, stdin);
fInName[strcspn(fInName, "\n")] = '\0';
}
// prompt for input until user enters something
while (strlen(fInName) < 1);
do
{
printf("What file would you like to output to? ");
// get outfile from user and remove trailing newline '\n' character
fgets(fOutName, 50, stdin);
fOutName[strcspn(fOutName, "\n")] = '\0';
}
// prompt for input until user enters something
while (strlen(fOutName) < 1);
FILE *fin = fopen(fInName, "r");
if (fin == NULL)
{
printf("Error: Cannot open input file %s.", fInName);
return 1;
}
else
{
printf("file found");
}
}
This is my algorithm for searching a term into a file.
void ricerca_file(char* frase){
char* prelievo = "";
file = fopen("*userpath*\\file.bin", "rb");
while((fgets(prelievo, sizeof(prelievo), file)) != NULL){
if((strstr(prelievo, frase)) != NULL)
printf("frase trovata!\n");
}
fclose(file);
printf("%s", prelievo);}
i ask the input of frase in this way:
char* frase = "";
printf("insert the term that you want to search..");
scanf("%s", frase);
and then i call the function with:
ricerca_file(frase);
The compiler gives me this error after i write the input (e.g the number 2):
prove1.exe: 0xC0000005: Access violation writing location 0x00F67BC3.
If there is a handler for this exception, the program may be safely
continued.
What am i doing wrong?
if it wasn't clear, i'm learning. But i didn't really got how to manage the search of a term into a file.
I guess that with this algorithm i can miss lots of matches because if i search for "hello", with the strstr function that moves 5 characters per cycle if i have a file with a text like this "abchelloabc" he will first find "abche" and will not find anything, while after the first cycle it will go to the "lloab" part and then "c". Am i right thinking that it works like that and this is wrong?
prelievo points to a string literal. This is constant data that cannot be written to. And sizeof(prelievo) will be 2 or 4 (or whatever size pointers are on your system), which is not what you want.
You'll need to instead point prelievo to an array of characters that can be modified:
char prelievo[1000];
The same problems and solution apply to frase:
char frase[1000];
You need to actually provide memory to save the string you scan into. Try something like this instead:
char frase[80];
printf("insert the term that you want to search..");
fgets(frase, 80, stdin);
This allocates enough space for 80 characters and then reads one line of input.
Please also check the results of all these functions: If they return an error, you should act appropriately.
what am I doing wrong:
regarding:
char* prelievo = "";
file = fopen("*userpath*\\file.bin", "rb");
while((fgets(prelievo, sizeof(prelievo), file)) != NULL){
...
The call to fgets() needs to have a pointer to a buffer as its' first parameter.
The 'prelievo' is only an uninitalized pointer.
suggestion 1)
char* prelievo = malloc( 1024 );
if ( prelievo ) {
file = fopen("*userpath*\\file.bin", "rb");
while((fgets(prelievo, sizeof(prelievo), file)) != NULL){
suggestion 2)
char prelievo[1024];
file = fopen("*userpath*\\file.bin", "rb");
while((fgets(prelievo, sizeof(prelievo), file)) != NULL){
This answer is not exactly related to your problem, but because you already got your Answers i will try to explain you about some problems if you ignore them.
If we do not check for errors/return and the program works fine this does not mean that the program is ok or safe.
Let's take the following scenario as an Example.
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
char *printFile(char *fileName){
size_t length,size;
char *buffer;
FILE *file;
file = fopen (fileName , "r" );
fseek (file , 0 , SEEK_END);
length = (size_t)ftell (file);
fseek (file , 0 , SEEK_SET);
buffer = malloc(length);
if (buffer == NULL){
fputs ("Memory error",stderr);
exit (2);
}
size = fread (buffer,1,length,file);
if (size != length){
fputs ("Reading error",stderr);
exit(3);
}
fclose (file);
return buffer;
}
int main (void) {
char *fileName = "test.txt";
char *stringToSearch = "Addams";
char *fileContent = printFile(fileName);
if (strstr(fileContent, stringToSearch)){
printf("%s was Found\n",stringToSearch);
}else{
printf("%s was not Found\n",stringToSearch);
}
free(fileContent);
return 0;
}
The file test.txt has the following content:
Michael Jackson
Bryan Addams
Jack Sparrow
So now if I run this program I get:
Addams was Found
Everything seems to be ok, but what happens if I try to share this program with someone ? Or what happens if I try to run it on another computer ?
well:
Segmentation fault (core dumped)
OMG, what did just happen now ? Simple,the file test.txt is missing and i did not check that in my program that's why.
Lets move on and create that file and run that program again:
Addams was not Found
Huh, I succeeded isn't ? Well not, valgrind has another opinion:
==3657== Invalid read of size 1
==3657== at 0x4C32FF4: strstr (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3657== by 0x400A2D: main (in /home/michi/program)
==3657== Address 0x54202b0 is 0 bytes after a block of size 0 alloc'd
==3657== at 0x4C2BBA0: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3657== by 0x40095E: printFile (in /home/michi/program)
==3657== by 0x400A16: main (in /home/michi/program)
What happens is that I try to read a file which was newly created without thinking if that file has some content and i performed a lot of codding on it.
I am using Code::Blocks and have set the command-line arugments via the IDE. I have also opened the executable with the proper argument and I can't manage to get a non-NULL on fopen() return. I've tried hard-coding the filename also with no success. The platform is Windows XP SP3.
The first is the one that fails, when i hardcoded it i used double backlash. Also i never knew if the second works because i never managed to start the process by opening the first one.
Obviously i put the text file in the same directory that the executable and rebuilt the executable many times, but it still doesn't work.
EDIT: I added the perror("fopen"); line in the if(finput==NULL) block. This is the output.
http://prntscr.com/h71pa
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define first_part_url "[url=http://magiccards.info/query?q="
#define second_part_url "&v=card&s=cname]"
#define end_bracket "[/url]\n"
#define output_file_prefix "output_"
char* get_card(FILE* finput);
int main(int n, char* arguments[])
{
FILE* finput;
FILE* foutput;
short int counter;
char* output_filename;
char* finalstring;
for(counter=1; counter<n; counter++)
{
finput=fopen(arguments[counter], "r");
if (finput==NULL)
{
printf("Unable to open ");
puts(arguments[counter]);
perror("fopen");
break;
}
strcpy(output_filename, output_file_prefix);
strcat(output_filename, arguments[counter]);
if((foutput=fopen(output_filename, "w"))==NULL)
{
printf("There was an error while trying to open ");
puts(arguments[counter]);
printf(" .\n");
break;
}
while(!feof(finput))
{
finalstring=get_card(finput);
fputs(finalstring, foutput);
while(((fgetc(finput))!='\n')||feof(finput));
}
printf("Autocarding ");
puts(arguments[counter]);
printf(" was a success.\n");
fclose(foutput);
}
if(finput!=NULL)
{
fclose(finput);
free(finalstring);
}
return 0;
}
char* get_card(FILE* finput)
{
char* currentcard;
char* finalstring;
currentcard=(char*)malloc(sizeof(char)*150);
fgets(currentcard, 150, finput);
/* Allocates the exact amount of space needed for the final string*/
finalstring=(char*)malloc(sizeof(char)*(strlen(first_part_url)+strlen(second_part_url)+strlen(end_bracket)+strlen(currentcard)));
/* Get all the final forum link together*/
strcat(finalstring, first_part_url);
strcat(finalstring, currentcard);
strcat(finalstring, second_part_url);
strcat(finalstring, end_bracket);
free(currentcard);
return finalstring;
}
The error you are getting, "No such file or directory" indicates that the file name you're trying to open doesn't exist.
In this case, it's probably because the program's current working directory is not the same as the directory containing the executable file.
This
finput=fopen(arguments[counter], "r");
Will only fail if you do not supply correct filenames (e.g. if there are non-ASCII characters in the names or the names do not include the correct path, fopen() opens files in the current directory if no path is specified in the file name).
This
output_filename=(char*)malloc(sizeof(arguments[counter]));
most likely does not allocate enough space for a name because arguments[counter] is a pointer, and sizeof() of a pointer is not the same as strlen(that_same_pointer) + 1.
This
output_filename=output_file_prefix;
loses the just allocated memory because you are reassigning the pointer output_filename to point to some other place, output_file_prefix ("output_").
After the above this
strcat(output_filename, arguments[counter]);
is likely going to crash your program because this is going to attempt to overwrite a string literal ("output_"), doing which causes undefined behavior per the C standard.
You have to allocate enough cumulative space for the strings that you want to concatenate and you have to concatenate them in the allocated space.
To save you even more trouble, here's another problem:
finput=fopen(arguments[counter], "r");
...
while(!feof(finput))
feof() only works after at least one read from a file. This has been asked ans answered multiple times.
Try changing
for(counter=1; counter<n; ++n)
{
to
for(counter=1; counter<n; ++counter)
It appears the code loops infinitely, therefore it would exhaust the possible elements in your argument array causing a NULL pointer to be returned.