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

时间:2012-03-13 10:04:31

标签: 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 );
    }
}

我正在使用C89进行编译,除了分段错误之外,似乎都可以正常工作。任何指导都将非常感谢。

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

4 个答案:

答案 0 :(得分:1)

对我而言,最明显的问题是您将char** monthGroup作为参数按值传递,然后将malloc传递给函数months,并且之后尝试在调用者函数中使用它。但是,由于您按值传递了该值,因此您只将malloc ed地址存储在monthGroup的本地副本中,该副本不会更改main中原始变量的值。

作为快速修复,您需要将指针传递给 monthGroup,而不是(当前值的副本):

int main (void){
  ...
  char** monthGroup;
  ...
  months( monthfp, &monthGroup );
  ...
}

void months ( FILE* monthfp, char*** monthGroup ){
  ...
  *monthGroup =  malloc( count * sizeof ( char* ));
  ...
}

这很难看(恕我直言,在实际代码中应该没有真正的理由使用char***),但至少朝着正确的方向迈出了一步。

然后,正如其他人正确提到的那样,您还应该重新考虑在循环中重新分配monthGroup并忘记之前的分配,留下内存泄漏和悬空指针的方法。当前代码循环中发生的事情是

// read the first bunch of text from the file
count++;
// count is now 1
monthGroup =  malloc( count * sizeof ( char* ));
// you allocated an array of size 1
monthGroup[count] = malloc( sizeof( buffer ) * sizeof( char ));
// you try to write to the element at index 1 - another segfault!
// should be monthGroup[count - 1] as below
strcpy(monthGroup[ count - 1 ], buffer );

即使使用上面提到的修复,在10次迭代之后,您仍然必须拥有10个元素的数组,其中前9个是悬空指针,只有10个指向有效地址。

答案 1 :(得分:1)

完成的代码将是:

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

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

    months(monthfp, &monthGroup);

    iter = monthGroup;

    /* We know that the last element is NULL, and that element will stop the while */
    while (*iter) {
        printf("%s", *iter);
        free(*iter);
        iter++;     
    }

    /* Remember that you were modifying iter, so you have to discard it */
    free(monthGroup);

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

        /* We realloc the buffer */
        *monthGroup = (char**)realloc(*monthGroup, count * sizeof(char**));

        /* Here I'm allocating an exact buffer by counting the length of the line using strlen */
        (*monthGroup)[count - 1] = (char*)malloc((strlen(buffer) + 1) * sizeof( char ));
        strcpy((*monthGroup)[count - 1], buffer);
    }

    /* We add a terminating NULL element here. Other possibility would be returning count. */
    count++;
    *monthGroup = (char**)realloc(*monthGroup, count * sizeof(char**));
    (*monthGroup)[count - 1] = NULL;
}

正如其他人所说,char***很难看。

答案 2 :(得分:1)

你的问题在于月份功能,特别是你对记忆如何运作的理解。

查看您的代码:

monthGroup =  malloc( count * sizeof ( char* ));

此行分配一块内存,相当于大小为char *的{​​{1}}数组。

count

这里,缓冲区的大小为monthGroup[count] = malloc( sizeof( buffer ) * sizeof( char )); sizeof (buffer)是不必要的)。这是一个问题:您将其分配给sizeof (char)。 C中的数组是零基数,这意味着数组:

monthGroup[count]

有元素:

int array [3];

array [0], array [1] and array [2] 超出了数组的内存。所以array [3]也在数组的内存之外。您想要monthGroup[count]。这将写入数组中的最后一个元素。

第二个问题是,每次进行第一次分配时,都会丢失先前分配的数据(这称为内存泄漏)及其包含的数据。

要解决此问题,有两种方法。

  1. 分配数组时,将旧数组的内容复制到新数组:

    oldarray = monthGroup;  monthGroup = malloc(count * sizeof(char *))  memcpy(monthGroup,oldarray,count-1 * sizeof(char *));  免费(oldarray);  monthGroup [count-1] = ....

    或使用monthGroup[count-1]

  2. 使用链接列表。这个复杂得多,但每次读取新项目时都不需要复制数组。

  3. 此外,monthGroup参数不会传递回调用者。将功能更改为:

    realloc

    或:

    char **months (FILE *fp)
    

    最后,调用者当前假定有12个条目并尝试打印每个条目。如果少于12或超过12,会发生什么?应对的一种方法是使用特殊指针来终止void months (FILE *fp, char ***ugly_pointer) 数组,NULL可以很好地完成。只需为数组分配一个额外的元素,并将最后一个元素设置为NULL。

答案 3 :(得分:0)

我立即看到的主要错误是,您对monthGroup的分配永远不会回到main