I'm trying to scan a line from a open file pointer, the one passed to the function is stdin. When I print out the value of input I get (null). Any ideas why fscanf is not saving the value? This is the code — also shown below:
char *ReadLineFile(FILE *infile){
char *input;
char buf[MAX];
//check if file pointer is at end of file
if(feof(infile))
return NULL;
//scan from file
fscanf(infile,"%s",input);
printf("%s",input);
input = (char *)malloc(strlen(input)+1);
//handle memory allocation errors
if (input == NULL){
printf("Error allocating memory\n");
return "error";
}
fclose(infile);
return input;
}
You must allocate memory for input before using fscanf(infile,"%s",input);.
fscanf(infile,"%s",input); asks fscanf to read a string and write it to input. Since input has not been assigned a value, let alone a value that points to memory allocated for this, the behavior is not defined.
Related
Like I said in the title I don't know how to print all the content of a .txt file in C.
Here's an incomplete function that I did:
void
print_from_file(items_t *ptr,char filemane[25]){
char *string_temp;
FILE *fptr;
fptr=fopen(filemane, "r");
if(fptr){
while(!feof(fptr)){
string_temp=malloc(sizeof(char*));
fscanf(fptr,"\n %[a-z | A-Z | 0-9/,.€#*]",string_temp);
printf("%s\n",string_temp);
string_temp=NULL;
}
}
fclose(fptr);
}
I'm pretty sure that there's errors in the fscanf because sometimes it doesn't exit the loop.
Can anyone please correct this?
You're using malloc wrong. Passing sizeof(char*) to malloc means you are only giving your string the amount of memory it would take to hold a pointer to a character(array). So currently, by writing into memory you have not allocated, you have undefined behavior. It is also highly advisable to perform checks on file lenght and otherwise make sure that you do not write more into the string then you allocated to it.
Instead, do something like this:
string_temp=malloc(100*sizeof(char)); // Enough space for 99 characters (99 chars + '\0' terminator)
There are several things to fix in your code.
First of all, you should always check if a file has been opened correctly.
Example:
FILE *fp; //file pointer
if((fp = fopen("file.txt", "r") == NULL) { //check opening
printf("Could not open file"); //or use perror()
exit(0);
}
Also, remember that scanf() and fscanf() return the number of elements they have read. So, for example, if you scan the file one word at a time, you could simplify your program by looping while fscanf(..) == 1.
As a final note, remember to allocate dynamic memory correctly.
You do not want to allocate memory based on a pointer to char size, in fact, you're gonna wanna allocate 1 byte for each character of the string, + 1 for the terminator.
Example:
char name[55];
char * name2;
//To make them of the same size:
name2 = malloc(sizeof(*char)); **WRONG**
name2 = malloc(sizeof(char) * 55); //OK
I have a function that receives the name of a file as an argument.
The idea is to read each word in the given file and save each one in a linked list (as a struct with a value and a pointer to the next struct).
I could get it working for small files, but when I give a big .txt file I get a segmentation fault.
Using gdb I could figure out that this happens at the while(fscanf(fi, "%s", value) != EOF){ line.
For some reason when the file is bigger the fscanf() segfaults.
As I could figure out the linked list part, here I pasted just enough code to compile and for you to see my problem.
So my question are:
Why fscanf() segfauts with big .txt files (thousands of words), but not with small file (ten words)?
By the way, is there a better way to check for the end of the file?
Thanks in advance.
bool read(const char* file){
// open file
FILE* fi = fopen(file, "r"); //file is a variable that contains the name of the file to be opened
if (fi == NULL)
{
return false;
}
// malloc for value
char* value = malloc(sizeof(int));
// fscanf() until the end of the file
while(fscanf(fi, "%s", value) != EOF){ // HERE IS MY PROBLEM
// some code for the linked list
// where the value will be saved at the linked list
}
// free space
free(value);
// close the file
fclose(fi);
return true;
}
No, here is your problem:
char* value = malloc(sizeof(int)); // <<<<<<< You allocate only place for an int
while(fscanf(fi, "%s", value) != EOF){ // <<<<<<< but you read a huge string
So you end up with a buffer overflow !
You have to make sure that you never overflow the size of your buffer by setting some limits. For example by using the width field of fscanf() to indicate max size of chars to be read for the string:
char* value = malloc(512); // Allocate your buffer
while(fscanf(fi, "%511s", value) != EOF){ // read max 511 chars + 1 char for terminating 0
...
(disclaimer: simplified explanation)
A char* is a pointer to an address of memory. It specifies that it points to an array of characters. A malloc call reserves a block of memory of a certain size.
Your line
char* value = malloc(sizeof(int));
creates a character array that can hold 4 characters (as an int is 4 bytes long generally). And for it to be a complete string the last character has to be a NULL terminator '\0', So really it can only hold 3 readable characters.
You should make that malloc create a block of memory that is larger than the biggest string in the file. Or you could use another safer method such as fgets : http://www.cplusplus.com/reference/cstdio/fgets/
I have a procedure readTokens() which takes a file and an array and tokenizes the file and puts the things into the array but when I access the array, it is full of the last element. why? here is my readTokens() method:
void
readTokens(char *fileName, char** a[])
{
FILE *fp;
char *token;
int count = 0;
fp = fopen(fileName, "r");
if (fp == 0)
{
fprintf(stderr,"file %s could not be opened for reading\n", fileName);
exit(1);
}
token = readLine(fp);
while(!feof(fp))
{
a[count] = token;
++count;
free(token);
token = readLine(fp);
}
fclose(fp);
}
You should not call free(token), since you still have a pointer to it in a[count]. Since you're freeing it, that memory can be reused, and apparently it's being used when readLine() reads the next line. So each time you read a line, it reuses the same memory and overwrites it with the next line. As a result, all elements of a[] contain pointers to the same line.
a[count] = token doesn't make a copy of the token, it simply assigns the pointer.
This all assumes that readLine() uses malloc() to allocate the memory for the line it reads. If it doesn't, then it's even worse, since you must not call free() on memory that wasn't allocated with malloc() or calloc().
It's possible that readLine() is just using a static array variable, which would also explain why all your lines are the same. If you don't want it to keep overwriting the token, you need to make a copy of it in readTokens(). It would help if you posted the definition of readLine().
I need to read in a file. The first line of the file is the number of lines in the file and it returns an array of strings, with the last element being a NULL indicating the end of the array.
char **read_file(char *fname)
{
char **dict;
printf("Reading %s\n", fname);
FILE *d = fopen(fname, "r");
if (! d) return NULL;
// Get the number of lines in the file
//the first line in the file is the number of lines, so I have to get 0th element
char *size;
fscanf(d, "%s[^\n]", size);
int filesize = atoi(size);
// Allocate memory for the array of character pointers
dict = NULL; // Change this
// Read in the rest of the file, allocting memory for each string
// as we go.
// NULL termination. Last entry in the array should be NULL.
printf("Done\n");
return dict;
}
I put some comments because I know that's what I'm to do, but I can't seem to figure out how to put it in actual code.
To solve this problem you need to do one of two things.
Read the file as characters then convert to integers.
Read the file directly as integers.
For the first, you would use freed into a char array and then use atoi to convert to integer.
For the second, you would use fscanf and use the %d specify to read directly into an int variable;
fscanf does not allocate memory for you. Passing it a random pointer as you have will only cause trouble. (I recommend avoid fscanf).
The question code has a flaw:
char *size;
fscanf(d, "%s[^\n]", size);
Although the above may compile, it will not function as expected at runtime. The problem is that fscanf() needs the memory address of where to write the parsed value. While size is a pointer that can store a memory address, it is uninitialized, and points to no specific memory in the process' memory map.
The following may be a better replacement:
fscanf(d, " %d%*c", &filesize);
See my version of the spoiler code here
I have a function that reads an input file and is supposed to modify the contents of a char** and a int*. The function is as follows:
void
input_parser(arguments* args, char** input, int* files) {
char buffer[MAX];
FILE *fr;
fr = fopen(args->file,"r");
if (fr == NULL) {
printf("No correct input file was entered\n");
exit(0);
}
while(fgets(buffer,MAX,fr) != NULL) {
input[*files] = strtok(buffer,"\n");
(*files)++;
}
fclose(fr);
return;
}
I have defined input and files as follows in the main program:
char* input[25];
files = 0;
I call the function as follows:
input_parser(args, input, &files);
The input file contains 3 lines as follows:
output1.xml
output2.xml
output3.xml
I notice that during the while loop the 'current' value is read correctly but stored in all input[*] resulting in:
input[0] = output3.xml
input[1] = output3.xml
input[2] = output3.xml
I would greatly appreciate if someone has any idea what is going wrong here.
The function is storing the address of the local variable buffer to each element in the input array: you need to copy the value returned by strtok(). The code as it stands is undefined behaviour as the buffer is out of scope once input_parser() returns, even it was not the logic is incorrect anyway.
If you have strdup(), you just use it:
input[*files] = strdup(strtok(buffer,"\n")); /* NULL check omitted. */
otherwise malloc() and strcpy(). Remember to free() the elements of input when no longer required.
Initialise input to be able determine which elements point to valid strings:
char* input[25] = { NULL };
You are going to end up having danging pointers, which are pointing inside your buffer after the buffer has been deallocated.