指针和malloc问题

指针和malloc问题,c,arrays,pointers,malloc,C,Arrays,Pointers,Malloc,我是C语言的新手,当数组和指针引用字符串时,我会被它们卡住。我可以要求输入2个数字(整数),然后返回我想要的数字(第一个数字或第二个数字),没有任何问题。但是当我请求名字并试图返回它们时,程序在我输入名字后崩溃,不知道为什么 理论上,我希望为第一个名字保留内存,然后将其扩展为包含第二个名字。谁能解释一下为什么会破裂 谢谢 #include <stdio.h> #include <stdlib.h> void main () { int NumItems =

我是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;

}
#包括
#包括
空干管()
{
int NumItems=0;
NumItems+=1;
char*NameList=malloc(sizeof(char[10])*NumItems);
printf(“请输入名称#1:\n”);
scanf(“%9s”,名称列表[0]);
fpurge(stdin);
NumItems+=1;
NameList=realloc(NameList,sizeof(char[10])*NumItems);
printf(“请输入名称#2:\n”);
scanf(“%9s”,名称列表[1]);
fpurge(stdin);
printf(“名字是:%s”,名字列表[0]);
printf(“第二个名称是:%s”,名称列表[1]);
返回0;
}

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

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

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

  char (*NameList)[10];
  NameList = malloc(10*sizeof(char)*NumItems);
char** NameList;
NameList = malloc (sizeof(char*) * NumItems);
free (NameList);
for (i = 0; i < NumItems; ++i)
    free (NameList[i]);

编辑:修复了一些编译错误。注意sizeof(char)并不是真正需要的,因为它总是1。不过,很明显。

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

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;

}
intmain(){
int i;
int NumItems=2;
/*Alocate每个位置都指向一个字符数组的变量*/
char**NameList=(char**)malloc(sizeof(char*)*NumItems);
/*对于每个位置,分配一个包含10个字符的数组*/
对于(i=0;i
我认为您的问题在于以下代码:

scanf("%9s", NameList[0]);
这里的问题是
scanf
要求作为存储结果的位置提供的参数必须是指针。如果您提供的东西不是指针,
scanf
会将其视为指针,并将内存写入随机位置,导致程序崩溃

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

  char (*NameList)[10];
  NameList = malloc(10*sizeof(char)*NumItems);
char** NameList;
NameList = malloc (sizeof(char*) * NumItems);
free (NameList);
for (i = 0; i < NumItems; ++i)
    free (NameList[i]);
接下来,需要为字符串分配存储空间。这很棘手,而且有点微妙,因为您必须进行两次分配。首先,您需要为阵列本身分配空间,您可以这样做:

  char (*NameList)[10];
  NameList = malloc(10*sizeof(char)*NumItems);
char** NameList;
NameList = malloc (sizeof(char*) * NumItems);
free (NameList);
for (i = 0; i < NumItems; ++i)
    free (NameList[i]);
这将为字符分配一个指针数组,但实际上并没有将这些数组中的指针设置为指向有效内存位置。要解决此问题,您需要遍历此数组,并将其所有元素设置为指向足够大以容纳字符串的缓冲区的指针—在本例中,长度为10的缓冲区:

int i;
for (i = 0; i < NumItems; ++i)
    NameList[i] = malloc (10); // Space for 10 characters
因为
NameList[0]
是一个
char*
字符,指向应该写入字符的缓冲区

一个关于你的代码的评论——而不是分配一个元素的数组,然后再把它重新分配给两个元素的数组,考虑只分配前面的所有空间。更清楚一点。另外,由于您现在处理的是一个

char*
s缓冲区,每个缓冲区都需要初始化以指向自己的缓冲区,因此如果您进行增量分配,则需要确保初始化您分配的所有新
char*
s以指向某个缓冲区。如果你一次只做一步,很有可能你会忘记设置指针,导致崩溃,而如果你提前这么做,就不会有这样的风险

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

for (i = 0; i < NumItems; ++i)
    free (NameList[i]);
free (NameList);
这将在运行时导致各种各样的糟糕情况,因为如果您首先释放顶级数组,然后在尝试迭代其内容时释放指针,您将读取不再拥有的内存


希望这有帮助

> P>也考虑只使用堆栈空间而不是使用<代码> MalOC 并动态分配堆空间:

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

通常,除非您需要动态调整大小的阵列,否则使用普通阵列要容易得多。

谢谢,我来试一试。我做的一个快速编辑是将&operator添加到我的scanf中,这实际上防止了它给我一个错误,但正如您所说,输出包括名字的第一个字母,然后是完整的第二个名字。所以第二次扫描重写了第一次扫描,当时我的意图是将它直接放在后面。@Eric Pi-我可能错了,但这段代码不违法吗
NameList
是一个数组,您不能为数组赋值。@模板:您可能是对的。首先分配指针数组,然后在循环中分配每个字符串的答案几乎肯定是更好的方法。我试图以尽可能少的改动通过外科手术修复示例代码。我