指针和malloc问题

时间:2011-02-12 22:35:51

标签: c arrays pointers malloc

我是C的新手,当他们引用字符串时我会遇到数组和指针。我可以要求输入2个数字(整数),然后返回我想要的数字(第一个数字或第二个数字),没有任何问题。但是,当我请求名称并尝试返回它们时,程序在输入第一个名称后崩溃,并且不确定原因。

理论上,我希望为名字保留内存,然后将其展开以包含第二个名称。任何人都可以解释为什么会中断吗?

谢谢!

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



void main ()
{
    int NumItems = 0;

    NumItems += 1;
    char* NameList = malloc(sizeof(char[10])*NumItems);
    printf("Please enter name #1: \n");
    scanf("%9s", NameList[0]);
    fpurge(stdin);

    NumItems += 1;
    NameList = realloc(NameList,sizeof(char[10])*NumItems);
    printf("Please enter name #2: \n");
    scanf("%9s", NameList[1]);
    fpurge(stdin);

    printf("The first name is: %s",NameList[0]);
    printf("The second name is: %s",NameList[1]);

    return 0;

}

4 个答案:

答案 0 :(得分:6)

我认为您的问题出在此代码中:

scanf("%9s", NameList[0]);

这里的问题是scanf要求您提供的参数作为存储结果的位置必须是指针。如果你提供的东西不是指针,那么scanf会将它视为现实,并且基本上将内存写入随机位置,从而导致程序崩溃。

解决此问题需要两个步骤。首先,您需要更改NameList的声明,使其不再是char *。原因是char *单个字符串,而您需要数组字符串。这将被定义为char **,指向char * s数组的指针。这可能如下所示:

char** NameList;

接下来,您需要为字符串分配存储空间。这很棘手,有点微妙,因为你必须做两次分配。首先,您需要为数组本身分配空间,您可以这样做:

NameList = malloc (sizeof(char*) * NumItems);

这会分配一个指向字符的指针数组,但实际上并没有将这些指针中的指针设置为指向有效的内存位置。要解决这个问题,你需要遍历这个数组,并将其所有元素设置为足够大的缓冲区指针,以保存字符串 - 在本例中,长度为10的缓冲区:

int i;
for (i = 0; i < NumItems; ++i)
    NameList[i] = malloc (10); // Space for 10 characters

现在,您可以致电

scanf("%9s", NameList[0]);

因为NameList[0]是指向应写入字符的缓冲区的char *

还有一个关于你的代码的注释 - 而不是分配一个元素的数组,然后再将它重新分配给两个元素的数组,考虑只是预先分配所有空间。它更清楚一点。此外,由于您现在正在处理char * s的缓冲区,每个缓冲区都需要初始化以指向其自己的缓冲区,如果您执行增量分配,则需要确保初始化所有您分配的新char *指向某个缓冲区。如果你一步一步这样做,你很可能忘记设置指针并导致崩溃,而如果你预先做到这一点就没有这样的风险。

当需要释放动态分配的内存时,您需要反向运行分配过程,首先释放动态分配的字符串缓冲区,然后释放顶级缓冲区。例如:

for (i = 0; i < NumItems; ++i)
    free (NameList[i]);
free (NameList);

这是必要的,因为free不能递归地工作。您需要显式释放所有分配的内存。

请注意,您执行编写如下代码:

free (NameList);
for (i = 0; i < NumItems; ++i)
    free (NameList[i]);

这会在运行时导致各种坏事,因为如果你先释放顶级数组,那么当你尝试迭代其内容释放指针时,你将会读取你不再拥有的内存。

希望这有帮助!

答案 1 :(得分:1)

您的NameList变量是char *,它是指向单个字符串的指针。 (char是单个字符,char *是单个字符串,char **是字符串数组。)

使用NameList [1]时,实际上是在索引字符串的第二个字符,而不是第二个字符串本身。

您应该改为分配数组字符串,如下所示:

  char (*NameList)[10];
  NameList = malloc(10*sizeof(char)*NumItems);

编辑:修正了一些编译错误。 (Sample code.)请注意,sizeof(char)并不是真正需要的,因为它始终是1.很高兴显而易见。

答案 2 :(得分:1)

如果你需要一个2d的字符数组(一个数组,其中每个元素都是一个char数组),你就是以错误的方式分配内存。正确的方法是:

int main(){

int i;
int NumItems = 2;

/* Alocate a variable which every position points to an array of character */
char ** NameList = (char **) malloc(sizeof(char *) * NumItems);

/* For each position, allocate an array of 10 characters */
for(i = 0; i < NumItems; i++){
    NameList[i] = (char *) malloc(sizeof(char) * 10);
}

printf("Please enter name #1: \n");
scanf("%s", NameList[0]);

printf("Please enter name #2: \n");
scanf("%s", NameList[1]);

printf("The first name is: %s",NameList[0]);
printf("The second name is: %s",NameList[1]);

/* Free allocated memory. Always a good practice and prevents memory leaks. */
for(i = 0; i < NumItems; i++){
    free(NameList[i]);
}
free(NameList);

return 0;

}

答案 3 :(得分:0)

还要考虑使用堆栈空间而不是使用malloc并动态分配堆空间:

#define NumItems 2
char NameList[NumItems][10];

printf("Please enter name #1: \n");
scanf("%9s", NameList[0]);

printf("Please enter name #2: \n");
scanf("%9s", NameList[1]);

printf("The first name is: %s",NameList[0]);
printf("The second name is: %s",NameList[0]);

通常,除非您需要动态大小的数组,否则使用普通数组要容易得多。