hope someone can assist. I had this program running perfectly, moved a few lines of code from one function to another and it all fell apart.
I've included a snippet below from the top of the function until segfault. It happily outputs "did we get here?" but not the next statement, I've spent so many hours trying to figure this that I can't remember the working build I had to begin with
It (at least the section below) is supposed to copy a whole textfile to a string
Morals of the story: working code is better than 'correct' code, always copy working code before you try to tweak it.
void validateFile(FILE* file, char** menuStore, char** submenuStore)
{
char* temp = NULL;
size_t size;
boolean flag = true;
char first;
/*Loop Counter*/
int i;
fseek(file, 0, SEEK_END);
size = ftell(file) * sizeof(char);
fseek(file, 0, SEEK_SET);
if ((temp = malloc(size)) == NULL)
{
printf("\nUnable to allocate Memory, Program exiting");
exit(EXIT_FAILURE);
} else
{
for (i = 0; i < (size / sizeof(char)); i++)
{
temp[i] = fgetc(file);
}
printf("\n did we get here?");
printf("\nFile loaded, validating...");
While reading from a file you should not use loop like this-
for (i = 0; i < (size / sizeof(char)); i++)
{
temp[i] = fgetc(file);
}
You should check for EOF condition while reading from a file-
i=0;
while((temp[i]=fgetc(file))!=EOF)
i++;
and make end of the string to \0. That is the better way to do.
temp[i]='\0';
Related
How can I retrieve an array of floating-point values from a file in C? This is the code I have used so far, but I am running into a segmentation fault(marked in my code where). If you see a less painful way of doing this that would be helpful as well.
The values are stored in the file with a single space after each value like so:
-667.0897114275529 544.6798599456312 -148.0586015260273 -323.4504101541069 .
// open file
FILE *fp;
fp = fopen(sig_file, "r");
if (fp == NULL){
printf("File opened incorrectly or is empty");
return 1;
}
// find file size
fseek(fp, 0L, SEEK_END);
long sz = ftell(fp);
fseek(fp, 0L, SEEK_SET);
// store file contents to f_contents
char *f_contents = 0;
f_contents = malloc(sz);
if (f_contents){
fread(f_contents, 1, sz, fp);
}
fclose(fp);
if (f_contents){
// find how many points are in the file
long pt_count = 0;
int i;
for (i=0; i<sz; i++){
if (f_contents[i] == ' '){
pt_count++;
}
}
// store points to a float array
double signal[pt_count];
char *pt;
pt = strtok(f_contents, " ");
// seg fault 11:
if (pt == NULL){
printf("error with pt");
return 1;
}
signal[0] = atof(pt);
//
for (i=1; i<pt_count; i++){
pt = strtok(NULL, " ");
signal[i] = atof(pt);
}
}
free(f_contents);
If you see a less painful way of doing this that would be helpful as well.
I haven't studied your code enough to identify the source of the segfault, because it should just be rewritten anyway. I might be inclined to do something more like this:
// open file
FILE *fp = fopen(sig_file, "r");
if (fp == NULL){
perror("fopen");
return 1;
}
size_t sz = 0;
for (int c = getc(fp); c != EOF; c = getc(fp)) {
if (c == ' ') sz++;
}
rewind(fp);
double signal[sz];
for (size_t i = 0; i < sz; i++) {
if (fscanf(fp, "%lf", &signal[i]) != 1) {
fclose(fp);
fputs("I/O error, malformed input, or premature EOF\n", stderr);
return 1;
}
}
fclose(fp);
If the file is long, then it might be worthwhile to read it all in one pass instead of counting elements first (and especially instead of slurping the entire file into memory). You can achieve such a one-pass read by storing the values in a more flexible data structure: some variety of linked list, or a dynamically allocated (and reallocated as necessary) array.
A linked list would need to be postprocessed into array form, but you might be able to use a dynamically allocated array as-is. You would need to use either a dynamically allocated array or a large-enough fixed-size array with a C implementation that does not support variable-length arrays, such as MS Visual Studio.
The first argument to strtok() must be a null-terminated string. fread() doesn't add a null terminator, and even if it did, you didn't allocate enough space for f_contents to hold it.
So use this code to allocate and fill in f_contents
f_contents = malloc(sz+1);
if (f_contents){
fread(f_contents, 1, sz, fp);
f_contents[sz] = '\0';
}
fclose(fp);
file looks like this:
abcd
efgh
ijkl
I want to read the file using C so that it read the last line first:
ijkl
efgh
abcd
I cannot seem to find a solution that does not use an array for storage. Please help.
edit0:
Thanks for all the answers. Just to let you know, I am the one creating this file. So, can I create in a way its in the reverse order? Is that possible?
It goes like this:
Seek to one byte before the end of the file using fseek. There's no guarantee that the last line will have an EOL so the last byte doesn't really matter.
Read one byte using fgetc.
If that byte is an EOL then the last line is a single empty line and you have it.
Use fseek again to go backwards two bytes and check that byte with fgetc.
Repeat the above until you find an EOL. When you have an EOL, the file pointer will be at the beginning of the next (from the end) line.
...
Profit.
Basically you have to keep doing (4) and (5) while keeping track of where you were when you found the beginning of a line so that you can seek back there before starting your scan for the beginning of the next line.
As long as you open your file in text mode you shouldn't have have to worry about multibyte EOLs on Windows (thanks for the reminder Mr. Lutz).
If you happen to be given a non-seekable input (such as a pipe), then you're out of luck unless you want to dump your input to a temporary file first.
So you can do it but it is rather ugly.
You could do pretty much the same thing using mmap and a pointer if you have mmap available and the "file" you're working with is mappable. The technique would be pretty much the same: start at the end and go backwards to find the end of the previous line.
Re: "I am the one creating this file. So, can I create in a way its in the reverse order? Is that possible?"
You'll run into the same sorts of problems but they'll be worse. Files in C are inherently sequential lists of bytes that start at the beginning and go to the end; you're trying to work against this fundamental property and going against the fundamentals is never fun.
Do you really need your data in a plain text file? Maybe you need text/plain as the final output but all the way through? You could store the data in an indexed binary file (possibly even an SQLite database) and then you'd only have to worry about keeping (or windowing) the index in memory and that's unlikely to be a problem (and if it is, use a "real" database); then, when you have all your lines, just reverse the index and away you go.
In pseudocode:
open input file
while (fgets () != NULL)
{
push line to stack
}
open output file
while (stack no empty)
{
pop stack
write popped line to file
}
The above is efficient, there is no seek (a slow operation) and the file is read sequentially. There are, however, two pitfalls to the above.
The first is the fgets call. The buffer supplied to fgets may not be big enough to hold a whole line from the input in which case you can do one of the following: read again and concatenate; push a partial line and add logic to the second half to fix up partial lines or wrap the line into a linked list and only push the linked list when a newline/eof is encountered.
The second pitfall will happen when the file is bigger than the available ram to hold the stack, in which case you'll need to write the stack structure to a temporary file whenever it reaches some threshold memory usage.
The following code should do the necessary inversion:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
FILE *fd;
char len[400];
int i;
char *filename = argv[1];
int ch;
int count;
fd = fopen(filename, "r");
fseek(fd, 0, SEEK_END);
while (ftell(fd) > 1 ){
fseek(fd, -2, SEEK_CUR);
if(ftell(fd) <= 2)
break;
ch =fgetc(fd);
count = 0;
while(ch != '\n'){
len[count++] = ch;
if(ftell(fd) < 2)
break;
fseek(fd, -2, SEEK_CUR);
ch =fgetc(fd);
}
for (i =count -1 ; i >= 0 && count > 0 ; i--)
printf("%c", len[i]);
printf("\n");
}
fclose(fd);
}
The following works for me on Linux, where the text file line separator is "\n".
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void readfileinreverse(FILE *fp)
{
int i, size, start, loop, counter;
char *buffer;
char line[256];
start = 0;
fseek(fp, 0, SEEK_END);
size = ftell(fp);
buffer = malloc((size+1) * sizeof(char));
for (i=0; i< size; i++)
{
fseek(fp, size-1-i, SEEK_SET);
buffer[i] = fgetc(fp);
if(buffer[i] == 10)
{
if(i != 0)
{
counter = 0;
for(loop = i; loop > start; loop--)
{
if((counter == 0) && (buffer[loop] == 10))
{
continue;
}
line[counter] = buffer[loop];
counter++;
}
line[counter] = 0;
start = i;
printf("%s\n",line);
}
}
}
if(i > start)
{
counter = 0;
for(loop = i; loop > start; loop--)
{
if((counter == 0) && ((buffer[loop] == 10) || (buffer[loop] == 0)))
{
continue;
}
line[counter] = buffer[loop];
counter++;
}
line[counter] = 0;
printf("%s\n",line);
return;
}
}
int main()
{
FILE *fp = fopen("./1.txt","r");
readfileinreverse(fp);
return 0;
}
Maybe , The does the trick , It reverse content of the file in whole
just like a string
Define a variable of type string with size of your file
Get Contents of the file and store in the variable
Use strrev() to reverse the string.
You can later on display the output or even write it to a file. The code goes like this:
#include <stdio.h>
#include <String.h>
int main(){
FILE *file;
char all[1000];
// give any name to read in reverse order
file = fopen("anyFile.txt","r");
// gets all the content and stores in variable all
fscanf(file,"%[]",all);
// Content of the file
printf("Content Of the file %s",all);
// reverse the string
printf("%s",strrev(all));
fclose(file);
return 0;
}
I know this question has been awnsered, but the accepted awnser does not contain a code snippet and the other snippets feel too complex.
This is my implementation:
#include <stdio.h>
long file_size(FILE* f) {
fseek(f, 0, SEEK_END); // seek to end of file
long size = ftell(f); // get current file pointer
fseek(f, 0, SEEK_SET); // seek back to beginning of file
return size;
}
int main(int argc, char* argv[]) {
FILE *in_file = fopen(argv[1], "r");
long in_file_size = file_size(in_file);
printf("Got file size: %ld\n", in_file_size);
// Start from end of file
fseek(in_file, -1, SEEK_END); // seek to end of file
for (int i = in_file_size; i > 0; i--) {
char current_char = fgetc(in_file); // This progresses the seek location
printf("Got char: |%c| with hex: |%x|\n", current_char, current_char);
fseek(in_file, -2, SEEK_CUR); // Go back 2 bytes (1 to compensate)
}
printf("Done\n");
fclose(in_file);
}
I'm working on steganography program in Java. But I got advice that I be able to resolve this task better in C program. I would like to try it, but I'm pretty bad in C programing. For now I would like to read one gif file and find byte which is used as image separator (0x2c from GIF format).
I tried to write this program:
int main(int argc, char *argv[])
{
FILE *fileptr;
char *buffer;
long filelen = 0;
fileptr = fopen("D:/test.gif", "rb"); // Open the file in binary mode
fseek(fileptr, 0, SEEK_END); // Jump to the end of the file
filelen = ftell(fileptr); // Get the current byte offset in the file
rewind(fileptr); // Jump back to the beginning of the file
buffer = (char *)malloc((filelen+1)*sizeof(char)); // Enough memory for file + \0
fread(buffer, filelen, 1, fileptr); // Read in the entire file
fclose(fileptr); // Close the file
int i = 0;
for(i = 0; buffer[ i ]; i++)
{
if(buffer[i] == 0x2c)
{
printf("Next image");
}
}
return 0;
}
Could someone give me advice how to repair my loop?
Could someone give me advice how to repair my loop?
Option 1: Don't depend on the terminating null character.
for(i = 0; i < filelen; i++)
{
if(buffer[i] == 0x2c)
{
printf("Next image");
}
}
Option 2: Add the terminating null character before relying on it. This is potentially unreliable since you are reading a binary file that could have embedded null characters in it.
buffer[filelen] = '\0';
for(i = 0; buffer[ i ]; i++)
{
if(buffer[i] == 0x2c)
{
printf("Next image");
}
}
Similar to the 'for()' based answer, if you only need to check for a specific byte (0x2c), you can simply do something like the following (and not worry about null in the byte stream), using while().
i = 0;
while(i < filelen)
{
if(buffer[i++] == 0x2c)
{
printf("Next image");
}
}
I wrote a simple program that would open a csv file, read it, make a new csv file, and only write some of the columns (I don't want all of the columns and am hoping removing some will make the file more manageable). The file is 1.15GB, but fopen() doesn't have a problem with it. The segmentation fault happens in my while loop shortly after the first progress printf().
I tested on just the first few lines of the csv and the logic below does what I want. The strange section for when index == 0 is due to the last column being in the form (xxx, yyy)\n (the , in a comma separated value file is just ridiculous).
Here is the code, the while loop is the problem:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char** argv) {
long size;
FILE* inF = fopen("allCrimes.csv", "rb");
if (!inF) {
puts("fopen() error");
return 0;
}
fseek(inF, 0, SEEK_END);
size = ftell(inF);
rewind(inF);
printf("In file size = %ld bytes.\n", size);
char* buf = malloc((size+1)*sizeof(char));
if (fread(buf, 1, size, inF) != size) {
puts("fread() error");
return 0;
}
fclose(inF);
buf[size] = '\0';
FILE *outF = fopen("lessColumns.csv", "w");
if (!outF) {
puts("fopen() error");
return 0;
}
int index = 0;
char* currComma = strchr(buf, ',');
fwrite(buf, 1, (int)(currComma-buf), outF);
int progress = 0;
while (currComma != NULL) {
index++;
index = (index%14 == 0) ? 0 : index;
progress++;
if (progress%1000 == 0) printf("%d\n", progress/1000);
int start = (int)(currComma-buf);
currComma = strchr(currComma+1, ',');
if (!currComma) break;
if ((index >= 3 && index <= 10) || index == 13) continue;
int end = (int)(currComma-buf);
int endMinusStart = end-start;
char* newEntry = malloc((endMinusStart+1)*sizeof(char));
strncpy(newEntry, buf+start, endMinusStart);
newEntry[end+1] = '\0';
if (index == 0) {
char* findNewLine = strchr(newEntry, '\n');
int newLinePos = (int)(findNewLine-newEntry);
char* modifiedNewEntry = malloc((strlen(newEntry)-newLinePos+1)*sizeof(char));
strcpy(modifiedNewEntry, newEntry+newLinePos);
fwrite(modifiedNewEntry, 1, strlen(modifiedNewEntry), outF);
}
else fwrite(newEntry, 1, end-start, outF);
}
fclose(outF);
return 0;
}
Edit: It turned out the problem was that the csv file had , in places I was not expecting which caused the logic to fail. I ended up writing a new parser that removes lines with the incorrect number of commas. It removed 243,875 lines (about 4% of the file). I'll post that code instead as it at least reflects some of the comments about free():
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char** argv) {
long size;
FILE* inF = fopen("allCrimes.csv", "rb");
if (!inF) {
puts("fopen() error");
return 0;
}
fseek(inF, 0, SEEK_END);
size = ftell(inF);
rewind(inF);
printf("In file size = %ld bytes.\n", size);
char* buf = malloc((size+1)*sizeof(char));
if (fread(buf, 1, size, inF) != size) {
puts("fread() error");
return 0;
}
fclose(inF);
buf[size] = '\0';
FILE *outF = fopen("uniformCommaCount.csv", "w");
if (!outF) {
puts("fopen() error");
return 0;
}
int numOmitted = 0;
int start = 0;
while (1) {
char* currNewLine = strchr(buf+start, '\n');
if (!currNewLine) {
puts("Done");
break;
}
int end = (int)(currNewLine-buf);
char* entry = malloc((end-start+2)*sizeof(char));
strncpy(entry, buf+start, end-start+1);
entry[end-start+1] = '\0';
int commaCount = 0;
char* commaPointer = entry;
for (; *commaPointer; commaPointer++) if (*commaPointer == ',') commaCount++;
if (commaCount == 14) fwrite(entry, 1, end-start+1, outF);
else numOmitted++;
free(entry);
start = end+1;
}
fclose(outF);
printf("Omitted %d lines\n", numOmitted);
return 0;
}
you're malloc'ing but never freeing. possibly you run out of memomry, one of your mallocs returns NULL, and the subsequent call to str(n)cpy segfaults.
adding free(newEntry);, free(modifiedNewEntry); immediately after the respective fwrite calls should solve your memory shortage.
also note that inside your loop you compute offsets into the buffer buf which contains the whole file. these offsets are held in variables of type int whose maximum value on your system may be too small for the numbers you are handling. also note that adding large ints may result in a negative value which is another possible cause of the segfault (negative offsets into buf take you to some address outside the buffer possibly not even readable).
The malloc(3) function can (and sometimes does) fail.
At least code something like
char* buf = malloc(size+1);
if (!buf) {
fprintf(stderr, "failed to malloc %d bytes - %s\n",
size+1, strerror(errno));
exit (EXIT_FAILURE);
}
And I strongly suggest to clear with memset(buf, 0, size+1) the successful result of a malloc (or otherwise use calloc ....), not only because the following fread could fail (which you are testing) but to ease debugging and reproducibility.
and likewise for every other calls to malloc or calloc (you should always test them against failure)....
Notice that by definition sizeof(char) is always 1. Hence I removed it.
As others pointed out, you have a memory leak because you don't call free appropriately. A tool like valgrind could help.
You need to learn how to use the debugger (e.g. gdb). Don't forget to compile with all warnings and debugging information (e.g. gcc -Wall -g). And improve your code till you get no warnings.
Knowing how to use a debugger is an essential required skill when programming (particularly in C or C++). That debugging skill (and ability to use the debugger) will be useful in every C or C++ program you contribute to.
BTW, you could read your file line by line with getline(3) (which can also fail and you should test that).
file looks like this:
abcd
efgh
ijkl
I want to read the file using C so that it read the last line first:
ijkl
efgh
abcd
I cannot seem to find a solution that does not use an array for storage. Please help.
edit0:
Thanks for all the answers. Just to let you know, I am the one creating this file. So, can I create in a way its in the reverse order? Is that possible?
It goes like this:
Seek to one byte before the end of the file using fseek. There's no guarantee that the last line will have an EOL so the last byte doesn't really matter.
Read one byte using fgetc.
If that byte is an EOL then the last line is a single empty line and you have it.
Use fseek again to go backwards two bytes and check that byte with fgetc.
Repeat the above until you find an EOL. When you have an EOL, the file pointer will be at the beginning of the next (from the end) line.
...
Profit.
Basically you have to keep doing (4) and (5) while keeping track of where you were when you found the beginning of a line so that you can seek back there before starting your scan for the beginning of the next line.
As long as you open your file in text mode you shouldn't have have to worry about multibyte EOLs on Windows (thanks for the reminder Mr. Lutz).
If you happen to be given a non-seekable input (such as a pipe), then you're out of luck unless you want to dump your input to a temporary file first.
So you can do it but it is rather ugly.
You could do pretty much the same thing using mmap and a pointer if you have mmap available and the "file" you're working with is mappable. The technique would be pretty much the same: start at the end and go backwards to find the end of the previous line.
Re: "I am the one creating this file. So, can I create in a way its in the reverse order? Is that possible?"
You'll run into the same sorts of problems but they'll be worse. Files in C are inherently sequential lists of bytes that start at the beginning and go to the end; you're trying to work against this fundamental property and going against the fundamentals is never fun.
Do you really need your data in a plain text file? Maybe you need text/plain as the final output but all the way through? You could store the data in an indexed binary file (possibly even an SQLite database) and then you'd only have to worry about keeping (or windowing) the index in memory and that's unlikely to be a problem (and if it is, use a "real" database); then, when you have all your lines, just reverse the index and away you go.
In pseudocode:
open input file
while (fgets () != NULL)
{
push line to stack
}
open output file
while (stack no empty)
{
pop stack
write popped line to file
}
The above is efficient, there is no seek (a slow operation) and the file is read sequentially. There are, however, two pitfalls to the above.
The first is the fgets call. The buffer supplied to fgets may not be big enough to hold a whole line from the input in which case you can do one of the following: read again and concatenate; push a partial line and add logic to the second half to fix up partial lines or wrap the line into a linked list and only push the linked list when a newline/eof is encountered.
The second pitfall will happen when the file is bigger than the available ram to hold the stack, in which case you'll need to write the stack structure to a temporary file whenever it reaches some threshold memory usage.
The following code should do the necessary inversion:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
FILE *fd;
char len[400];
int i;
char *filename = argv[1];
int ch;
int count;
fd = fopen(filename, "r");
fseek(fd, 0, SEEK_END);
while (ftell(fd) > 1 ){
fseek(fd, -2, SEEK_CUR);
if(ftell(fd) <= 2)
break;
ch =fgetc(fd);
count = 0;
while(ch != '\n'){
len[count++] = ch;
if(ftell(fd) < 2)
break;
fseek(fd, -2, SEEK_CUR);
ch =fgetc(fd);
}
for (i =count -1 ; i >= 0 && count > 0 ; i--)
printf("%c", len[i]);
printf("\n");
}
fclose(fd);
}
The following works for me on Linux, where the text file line separator is "\n".
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void readfileinreverse(FILE *fp)
{
int i, size, start, loop, counter;
char *buffer;
char line[256];
start = 0;
fseek(fp, 0, SEEK_END);
size = ftell(fp);
buffer = malloc((size+1) * sizeof(char));
for (i=0; i< size; i++)
{
fseek(fp, size-1-i, SEEK_SET);
buffer[i] = fgetc(fp);
if(buffer[i] == 10)
{
if(i != 0)
{
counter = 0;
for(loop = i; loop > start; loop--)
{
if((counter == 0) && (buffer[loop] == 10))
{
continue;
}
line[counter] = buffer[loop];
counter++;
}
line[counter] = 0;
start = i;
printf("%s\n",line);
}
}
}
if(i > start)
{
counter = 0;
for(loop = i; loop > start; loop--)
{
if((counter == 0) && ((buffer[loop] == 10) || (buffer[loop] == 0)))
{
continue;
}
line[counter] = buffer[loop];
counter++;
}
line[counter] = 0;
printf("%s\n",line);
return;
}
}
int main()
{
FILE *fp = fopen("./1.txt","r");
readfileinreverse(fp);
return 0;
}
Maybe , The does the trick , It reverse content of the file in whole
just like a string
Define a variable of type string with size of your file
Get Contents of the file and store in the variable
Use strrev() to reverse the string.
You can later on display the output or even write it to a file. The code goes like this:
#include <stdio.h>
#include <String.h>
int main(){
FILE *file;
char all[1000];
// give any name to read in reverse order
file = fopen("anyFile.txt","r");
// gets all the content and stores in variable all
fscanf(file,"%[]",all);
// Content of the file
printf("Content Of the file %s",all);
// reverse the string
printf("%s",strrev(all));
fclose(file);
return 0;
}
I know this question has been awnsered, but the accepted awnser does not contain a code snippet and the other snippets feel too complex.
This is my implementation:
#include <stdio.h>
long file_size(FILE* f) {
fseek(f, 0, SEEK_END); // seek to end of file
long size = ftell(f); // get current file pointer
fseek(f, 0, SEEK_SET); // seek back to beginning of file
return size;
}
int main(int argc, char* argv[]) {
FILE *in_file = fopen(argv[1], "r");
long in_file_size = file_size(in_file);
printf("Got file size: %ld\n", in_file_size);
// Start from end of file
fseek(in_file, -1, SEEK_END); // seek to end of file
for (int i = in_file_size; i > 0; i--) {
char current_char = fgetc(in_file); // This progresses the seek location
printf("Got char: |%c| with hex: |%x|\n", current_char, current_char);
fseek(in_file, -2, SEEK_CUR); // Go back 2 bytes (1 to compensate)
}
printf("Done\n");
fclose(in_file);
}