Reading from file of undefined length, storing in

2019-08-01 23:52发布

问题:

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; }

回答1:

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



回答2:

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.