1

I want to open a file, read its content and store it in an array using C code.

I did it on my Windows laptop and it works but when i try the code on my Raspberrypi i get segmentation faults. I've been trying for a while to debugm I'm quite new to C so I'm having trouble finding what I did wrong.

    char *readFile(char *fileName)
    {
        FILE *ptr_file;
        char *ptr_data;
        int n = 0;
        char c;

        ptr_file = fopen(fileName, "r");
        if(ptr_file == NULL)
        {
            perror("File could not be opened.\n");
            exit(EXIT_FAILURE);
        }
        fseek(ptr_file, 0, SEEK_END);
        long f_size = ftell(ptr_file);
        fseek(ptr_file,0, SEEK_SET);
        ptr_data = (char *)malloc(f_size+1);

if(ptr_data == NULL)
{
perror("MALLOC FAILED");
exit(EXIT_FAILURE);
}

        while((c = fgetc(ptr_file)) != EOF)
        {
                ptr_data[n++] = (char)c;

        }
        ptr_data[n] = '\0';
        fclose(ptr_file);
        return ptr_data;
    }

to me it seems like the segmentations fault appears in the while loop after the call to malloc.

Why does it work on my laptop and not on the raspberrypi?

at the same time i dont understand why i get segmentation faults on my RPi if id do this:

   int main(int argc, char *argv[])
            {
    char data[100] = {};
                FILE *ptr_file;
                char *ptr_data=data;
                int n = 0, i = 0;
                char c;

                ptr_file = fopen(fileName, "r");
                if(ptr_file == NULL)
                {
                    perror("File could not be opened.\n");
                    exit(EXIT_FAILURE);
                }

                while((c = fgetc(ptr_file)) != EOF)
                {
                        ptr_data[n++] = (char)c;

                }
                ptr_data[n] = '\0';
                while(i <n,i++)
    {
    printf("%c\n",data[i]);
    fclose(ptr_file);

        }

return 0; }

11
  • 4
    Check that the allocation actually succeeds. Also, don't cast the return of malloc. Commented Feb 4, 2014 at 10:42
  • check f_size must match the actual file size. Commented Feb 4, 2014 at 10:44
  • 4
    Reading a file char by char with fgetc is very inefficient. You'd better use fread. Commented Feb 4, 2014 at 10:44
  • 5
    char c; --> int c; Commented Feb 4, 2014 at 10:46
  • How can I do a check on f_size? more then knowing my own file size that is. also i use fgetc to eventually clear some specific chars.. edited my allocation check, forgot to put it in there. why should c be an int? and the casting, i guess ptr_data = malloc(sizeof*ptr_data * (f_size +1)) should work instead Commented Feb 4, 2014 at 11:19

2 Answers 2

2

There are some issues when reading text file on different environment. When writing a new line, for example, may consume 2 bytes on Windows, and just 1 on Linux. From an article:

Subclause 7.21.9.4 of the C Standard [ISO/IEC 9899:2011] specifies the following behavior for ftell() when opening a text file in text mode: For a text stream, its file position indicator contains unspecified information, usable by the fseek function for returning the file position indicator for the stream to its position at the time of the ftell call. Consequently, the return value of ftell() for streams opened in text mode should never be used for offset calculations other than in calls to fseek().

In another words, fseek and ftell function behavior may be different depending on which environment you're working with.
For further explanation you may read this topic: https://www.securecoding.cert.org/confluence/display/seccode/FIO14-C.+Understand+the+difference+between+text+mode+and+binary+mode+with+file+streams

Sign up to request clarification or add additional context in comments.

Comments

0

Maybe you should disable Linux memory overcommit. See this.

BTW, you might consider using open(2) to open your file, fstat(2) to get statistics, notably file size, about it, then mmap(2) to project the file into virtual memory by growing your address space.

int fd = open(fileName, O_RDONLY);
if (fd<0) { perror(fileName); exit(EXIT_FAILURE); };
struct stat fs;
memset (&fs, 0, sizeof(fs));
if (fstat(fd, &fs)) { perror("fstat"); exit(EXIT_FAILURE); };
long pgsz = sysconf(_SC_PAGE_SIZE); // a power of two
size_t roundedsz = (fs.st_size | (pgsz-1)) + 1; // round up the size
void* ad = mmap(NULL, roundedsz, PROT_READ, MAP_SHARED, fd, (off_t)0);
if (ad == MMAP_FAILED) { perror("mmap"); exit(EXIT_FAILURE); };

Then use ad instead of ptr_data (which becomes useless). Don't forget to call munmap and close when you are done...

You could close just after the mmap if you want to.

Read Advanced Linux Programming.

2 Comments

this is way out of my current knowledge of both linux and c code :S where do i begin?
I gave you precise references to help you. Please read them. Then ask some other question ....

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.