读取未定义长度的文件,存储在数组中,分段错误

时间:2014-02-04 10:38:22

标签: c linux segmentation-fault malloc

我想打开一个文件,阅读其内容并使用C代码将其存储在数组中。

我在我的Windows笔记本电脑上做了它并且它可以工作但是当我在我的Raspberrypi上尝试代码时,我得到了分段错误。我已经尝试了一段时间来调试我对C很新,所以我很难找到我做错了。

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

对我来说,似乎在调用malloc之后,while循环中出现了分段错误。

为什么它适用于我的笔记本电脑而不是覆盆子皮?

同时我不明白为什么我的RPi会出现分段错误,如果id这样做:

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

        }

返回0; }

2 个答案:

答案 0 :(得分:2)

在不同环境下阅读文本文件时存在一些问题。 例如,在编写新行时,Windows上可能会占用2个字节,而Linux上只占1个字节。 来自一篇文章:

  

C标准[ISO / IEC 9899:2011]的第7.21.9.4条规定了   在文本模式下打开文本文件时ftell()的以下行为:   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.因此,流的ftell()的返回值   在文本模式下打开不应该用于其他偏移计算   比调用fseek()。

换句话说,根据您正在使用的环境,fseek和ftell功能行为可能会有所不同。
有关进一步说明,您可以阅读本主题: https://www.securecoding.cert.org/confluence/display/seccode/FIO14-C.+Understand+the+difference+between+text+mode+and+binary+mode+with+file+streams

答案 1 :(得分:0)

也许你应该禁用Linux memory overcommit。 请参阅this

顺便说一下,您可以考虑使用open(2)打开文件,fstat(2)获取统计信息,特别是文件大小,然后mmap(2)将文件投影到virtual memory通过增长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); };

然后使用ad代替ptr_data(这变得毫无用处)。完成后不要忘记致电munmapclose ......

如果您愿意,可以在close之后mmap

阅读Advanced Linux Programming