我是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;
}
答案 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]);
通常,除非您需要动态大小的数组,否则使用普通数组要容易得多。