有人可以告诉我为什么我会在这个简单的C程序中出错吗?

时间:2010-03-24 05:04:01

标签: c malloc segmentation-fault

在我结束第一次循环后,我继续遇到段故障,对于我的生活,我不知道为什么。 我正在扫描的文件只有18行中的18个字符串。 我认为问题是我正在使用名为picks的双指针的方式,但我不确切知道为什么。 我只是试图扫描长度小于15个字符的字符串,所以我没有看到问题。有人可以帮忙。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LENGTH 100

int main( int argc,char *argv[] )
{

   char* string = malloc( 15*sizeof(char) );
   char** picks = malloc(15*sizeof(char*));
   FILE* pick_file = fopen( argv[l], "r" );
   int num_picks;


   for( num_picks=0 ; fgets( string, MAX_LENGTH, pick_file ) != NULL ; num_picks++ )
     {
       scanf( "%s", picks+num_picks );
     }
   //this is where i seg fault
   int x;
   for(x=0; x<num_picks;x++)
     printf("s\n", picks+x);
}

7 个答案:

答案 0 :(得分:9)

picks是一个指向指针的指针:这意味着它指向的东西本身就是指针。

执行此操作时:

char** picks = malloc(15*sizeof(char*));

你正在使picks指向一个15个指针的块 - 这就好了(尽管如此,因为你想读入 18 行,你真的需要18个这里代替15)。这意味着picks指向内存中的变量块,如下所示:

| picks (char **) | --------> | picks[0] (char *)  | ----> ?
                              | picks[1] (char *)  | ----> ?
                              | picks[2] (char *)  | ----> ?
                              | ...                |
                              | picks[14] (char *) | ----> ?

正如你所看到的那样,那15个char *指针现在都是非本地化的 - 它们并没有指向任何东西。在为那些人分配一些内存之前,你不能开始使用它们 - 你需要做这样的事情:

int i;
for (i = 0; i < 15; i++)
{
    picks[i] = malloc(15);
}

现在,之后,内存布局如下所示:

| picks (char **) | --------> | picks[0] (char *)  | ----> | picks[0][0] (char)  |
                                                           | picks[0][1] (char)  |
                                                           | ...                 |
                                                           | picks[0][14] (char) |

                              | picks[1] (char *)  | ----> | picks[1][0] (char)  |
                                                           | ...                 |

                              | ...                |

...现在您可以存放所有想要阅读的字符。

答案 1 :(得分:5)

  1. string只分配足够的内存来存储一个字符(sizeof(char))。如果你想存储更多的字符,你需要将sizeof(char)乘以你想要存储的字符串的大小,再加上一个用于结尾的空字符。

  2. 而不是:

    char** picks = malloc(15*sizeof(char));
    

    你想这样做:

    char** picks = malloc(15*sizeof(char*));
    

    picks数组的每个元素都需要足够大以容纳指针。

答案 2 :(得分:3)

首先,在C字符串中存储为byte(char)数组,并且必须进行分配。在这种情况下,用于读取文件的字符串应分配给MAX_LENGTH + 1(字符串终止符为+1,\ 0)字符:

char* string = malloc( (MAX_LENGTH+1) * sizeof(char) );

这将为最大长度的字符串分配足够的内存:MAX_LENGTH。

另一个问题是指针数组char **picks未分配用于存储您希望阅读的18个字符串:

必须为15个char指针(char *)分配,它们也必须在第一个循环中分配。

int main( int argc,char *argv[] )
{
   ...
   char* string = malloc( (MAX_LENGTH+1) * sizeof(char) );
   char** picks = malloc(15*sizeof(char *));
   FILE* pick_file = fopen( argv[l], "r" );
   int num_picks;

   for( num_picks=0 ; fgets( string, MAX_LENGTH, pick_file ) != NULL ; num_picks++ )
     {
       printf("pick a/an %s ", string );
       //--- allocate the char array to store the current string
       picks[num_picks] = malloc (15 * sizeof(char));
       sscanf(string, "%s", picks[num_picks] );
     }

   for(int x=0; x<num_picks;x++)
     printf("%s\n", picks[x]);
}

您还必须测试malloc()返回值,并且您可能希望测试文件内容是否真的符合预期,并且不包含更多行或超过15个字符的行。


scanf()读取标准输入,我用sscanf()替换它,并在第二个printf()中添加缺少的'%'符号。

答案 3 :(得分:1)

  • string指向的位置仅为一个字符分配空间,但您尝试读取最多MAX_LENGTH个字符;
  • picks指向的位置仅为15个char *指针分配空间,但您显然希望在那里存储指向18个字符串的指针;
  • picks指向的位置已分配但从未初始化。在将它们交给scanf之前,你需要让那些15(或18)个指针实际指向某些东西。

在这种情况下,实际上根本不需要动态分配 - 你可以用数组做你想做的事情:

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

#define MAX_LENGTH 100
#define MAX_LINES 18

int main(int argc, char *argv[])
{
    char string[MAX_LENGTH];
    char picks[MAX_LINES][MAX_LENGTH];
    FILE *pick_file = NULL;
    int num_picks;

    if (argc > 1)
        pick_file = fopen(argv[1], "r");

    if (pick_file == NULL)
        return 1;

    for (num_picks = 0; num_picks < MAX_LINES && fgets(string, MAX_LENGTH, pick_file) != NULL; num_picks++)
    {
        printf("pick a/an %s ", string);
        scanf("%s", picks[num_picks]);
    }

    int x;
    for (x = 0; x < num_picks; x++)
        printf("%s\n", picks[x]);

    return 0;
}

答案 4 :(得分:0)

是因为在线:
for( num_picks=0 ; fgets( string, MAX_LENGTH, pick_file ) != NULL ; num_picks++ )
MAX_LENGTH是100,但您正在读取变量string,它只能包含一个字符?

答案 5 :(得分:0)

您正为char*分配一个十五picks的数组:

char** picks = malloc(15*sizeof(char*));

现在picks有足够的空间来存储十五char*,但你实际上从未在内部放置任何指向应该包含读取字符的内存的指针。

您需要为将使用scanf读取的字符串分配内存。目前scanf只是将数据写入picks中指针(尚未初始化为指向任何有用位置)指向的位置。

答案 6 :(得分:0)

你在这里遇到了段错误。

scanf( "%s", picks+num_picks );

代替这样做,

for( num_picks=0 ; fgets( string, MAX_LENGTH, pick_file ) != NULL ; num_picks++ )
 {
   pics[num_picks] = (char* )malloc(100);
   scanf( "%s", picks+num_picks );
 }

问题是,你分配**pics来保存15个字符串,但你读取字符串而不为这些字符串分配空间。确保你总是读入已分配的指针。