40个简单的线条,1个烦人的分段故障.我真的不知道现在还要转向何处

fmd*_*dub 2 c segmentation-fault

我很抱歉,如果这是浪费时间和/或不应该在这个网站上应该是什么,但我有点想法...我仍然是编程新手,无法掌握我的老师为了指导,所以...到互联网!

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

void months( FILE* monthfp, char** monthGroup );

int main (void){
        FILE *monthfp; /*to be used for reading in months from months.txt*/
        char** monthGroup;
        int i;

        if (( monthfp = fopen ( "months.txt", "r" )) == NULL ){
            printf( "unable to open months.txt. \n" );
            exit ( 1 );
    }

    months( monthfp, monthGroup );

/*test so far*/
    for ( i = 0; i < 12; i++ ){
            printf( "%s", monthGroup[i] );
    }

    fclose( monthfp );


}
void months ( FILE* monthfp, char** monthGroup ){
/*****************************************
    name: months
    input: input file, data array
    returns: No return. Modifies array.
*/
    char buffer[50];
    int count = 0;

    while ( fgets( buffer, sizeof(buffer), monthfp ) != NULL ){
            count++;
            monthGroup =  malloc( count * sizeof ( char* ));
            monthGroup[count] = malloc( sizeof( buffer ) * sizeof( char ));
            strcpy(monthGroup[ count - 1 ], buffer );
    }
}
Run Code Online (Sandbox Code Playgroud)

我在C89编译,一切似乎都有效,除了分段错误.非常感谢任何指导.

编辑 感谢所有花时间提供一些洞察力的人,我一直无法理解.在异乡的一个长老村里,我感觉自己像个小孩子.非常感谢礼貌和指导.

Kar*_*tel 8

我担心你没有意识到你做得多好.坐下来,这将是很长的.欢迎来到C.

char** monthGroup
Run Code Online (Sandbox Code Playgroud)

所有这些真正意味着"指向指针char".但是,C有许多原因可以指向某些内容.在你的情况下,"内部"指向是这样你实际上可以指向内存中的s 序列char(你通常将其视为"字符串",C正确地没有),而"外部"指向是这样的您可以指向那些char*s 的序列,并将该序列视为"数组"(即使它不是 ;您将动态分配它).

这就是问题所在:当你传入char**来自main它的内容时,它实际上并没有指向任何东西."那很好",你说; "该功能将使它指向我将分配的某些内存malloc()".

不.

C按值传递所有内容.在char**months接收到的是一个副本中的char**main局部变量的块.你覆盖指针(带有malloc调用的结果),写一些指向指向内存的指针(更多malloc结果),将一些数据复制到那些指向内存的块中......然后,在函数的末尾,参数monthGroup(它是一个局部变量months)不再存在,并且您丢失了所有数据,并且monthGroupmain中的变量在指向任何内容时仍然保持不变.当你试图使用它就像它指向什么东西一样,繁荣你已经死了.

那么我们如何解决这个问题呢?当然,对于另一个指向级别,C恰当地没有 "通过引用传递",所以我们必须伪造它.我们接受char***,并通过它&monthGroup.这仍然是一个复制值,但它直接指向main(在堆栈上)调用的局部变量存储.这让我们可以编写一个可见的值main.我们将第一个malloc结果分配给*monthGroup,并将指针写入该存储(*monthGroup[count])等.

除了我们真的不想这样做,因为它非常难看,令人困惑,很难做对.让我们做一些你应该做的非常明显的事情并且基本指令几乎不强调:使用函数的返回值来返回计算结果 - 这就是为什么它被称为返回值.

也就是说,我们设置了一个char**in months(接受任何类型的参数),返回它,并用它来初始化main.

我们完了吗?.

您仍然有一些逻辑错误:

  • 您在while循环中重新分配"外部"层.那显然不是你想要的; 你要分配几个"字符串",但只分配一个"数组",以便分配超出循环.否则,你每次扔掉(没有正确释放它们!)旧数组.

实际上,你确实想要做这样的事情,但这只是因为你事先并不知道你需要多少元素.问题是新的分配就是 - 一个新的分配 - 不包含先前设置的指针.

幸运的是,C有一个解决方案:realloc.这将分配新内存,复制旧内容(指向您分配的"字符串"的指针),并释放旧块.万岁!更好的是,如果我们为"旧记忆"给它一个NULL指针,realloc就会表现得像malloc.这让我们可以避免特殊的套管循环.

  • count错误地使用了该值.第一次通过循环,你将count增加到1,分配一些空间monthGroup[1]指向,然后尝试写入指向的空间monthGroup[0],这是从未设置过的.您想要为刚刚分配的"字符串"写入相同的空间.(BTW,sizeof(char)没用:它总是 1. 即使你的系统使用超过8位代表一个字符!这char是你系统上的基本存储单元.)

除非没有,因为有一种更简单的方法:用于strdup获取指向缓​​冲区的已分配副本的指针.

char** months(FILE* monthfp) {
    char buffer[50];
    int count = 0;
    char** monthGroup = NULL;

    while (fgets(buffer, sizeof(buffer), monthfp) != NULL) {
        // (re-)allocate the storage:
        monthGroup = realloc(monthGroup, count * sizeof(char*));
        // ask for a duplicate of the buffer contents, and put a pointer to the
        // duplicate sequence into the last element of the storage:
        monthGroup[count - 1] = strdup(buffer);
    }

    return monthGroup;
}
Run Code Online (Sandbox Code Playgroud)

调整main匹配留作(希望是微不足道的)练习.还请阅读文档reallocstrdup.

我们完了吗?没有.

你仍然应该检查NULL来自realloc和的返回strdup(因为它们都试图分配内存,因此可能在C中以这种方式失败),并且你仍然需要代码来free分配内存.

并且,正如其他人所指出的,你不应该假设将有12个月.如果你可以假设,你不会monthGroup在第一时间动态分配; 你只需要使用一个数组.所以你需要以某种方式传递结果"数组"的大小(向结尾添加一个显式的NULL指针是一种方式;另一种是做可怕的丑陋的事情,传入一个char***,并使用返回值来计算大小) .