我正在尝试创建和存储一个char*
数组。
所以,首先我试了这个:
int main() {
char* values[3];
values[0] = "Hello";
values[1] = "Mew meww";
values[2] = "Miau miau =3";
for(int i=0; i<sizeof(values); i++)
printf("%s", values[i]);
}
与以下输出一起工作:
你好海鸥海鸥Miau Miau =3
如果我尝试:
printf("%s", "Tamaño del diccionario: ");
int tam;
scanf("%i", &tam);
char* dic[tam];
Word words[tam];
for(int i=0; i<tam; i++)
{
printf("Palabra %d: ",(i+1));
scanf("%32s", &dic[i]);
}
for(int i=0; i<tam; i++)
{
printf("%s",dic[i]);
printf("n");
}
显示不清晰的内容,如"0xassdfsdf"
我怎么做才能把它存储在内存中?
#include <stdio.h>
#include <stdlib.h>
int main(){
char* values[3];
values[0] = "Hello";
values[1] = "Mew meww";
values[2] = "Miau miau =3";
for(int i=0; i<sizeof(values)/sizeof(*values); i++)
printf("%sn", values[i]);
printf("%s", "Size for dictionary: ");
int tam;
scanf("%i", &tam);
char *dic[tam];
for(int i=0; i<tam; i++){
printf("Palabra %d: ",(i+1));
dic[i] = malloc(33);
scanf("%32s", dic[i]);
}
for(int i=0; i<tam; i++){
printf("%sn", dic[i]);
free(dic[i]);
}
return 0;
}
有一个问题是
scanf("%32s", &dic[i]);
应该是
scanf("%32s", dic[i]);
,因为数组包含指向存储的指针,而不是存储本身,你应该传递给scanf
的是这个指针。实际上,char*
只是一个4字节的指针。数组char* dic[tam]
包含了一些这样的指针,所以dic[0]
是一个指向char
的4字节指针,&dic[0]
是这个指针的地址。那么你的
scanf("%32s", &dic[i]);
只会覆盖这个指针,并且会破坏它之后的内存。
另一个问题是,你没有初始化数组,所以它不指向任何存储。
char* dic[tam];
数组包含指向内存中随机位置的指针。
scanf("%32s", &dic[i]);
很可能根本就失败了。因此,在printf
中,您可以打印指向内存中随机位置的指针。
一个(坏的)解决方案是:
for(int i=0; i<tam; i++)
{
printf("Palabra %d: ",(i+1));
dic[i] = new char [1000]; // here you assign it some storage
scanf("%32s", dic[i]); // NOT &dic[i]
}
或(稍好)
for(int i=0; i<tam; i++)
{
printf("Palabra %d: ",(i+1));
char buffer [1000]; // temporal storage arguably large enough
scanf("%32s", buffer);
dic[i] = new char [strlen (buffer) + 1]; // storage of the right size to hold the string
strcpy (dic[i], buf); // copy the data to this new storage
}
对于您的两个示例,要理解的关键是char *
值在内存中存储字节的地址。按照惯例,C字符串被表示为指向字符串第一个字节的指针,用空字节标记结束。当你将常量字符串赋值到数组中时,编译器会分配必要的内存并将指针放入数组中,但是当你不使用常量时,你要负责分配缓冲区来存储字符串,然后自己将指针存储到数组中。
在第二个示例中,您为几个指向char
的指针分配了存储空间,但是您没有使这些指针指向有效的缓冲区,因此访问它们要么返回垃圾,要么使程序崩溃。有(至少)两种方法可以解决这个问题:要么在堆栈上分配一个固定大小的缓冲区并将数据存储在那里,要么使用malloc
从堆中动态分配内存。
前者具有自动处理缓冲区释放的优点,但需要您在编译时决定为每个字符串分配多少内存:
char* dic[tam];
char buf[tam * 32]; // allocate 32 bytes per element.
for (int i = 0; i < tam; i++) {
// Make the pointers in ``dic`` refer to 32-byte offsets into the buffer.
dic[tam] = &(buf[tam * 32]);
}
您还可以使用malloc
动态分配。实际上,您也可以这样分配一个大的tam * 32
缓冲区,但为了方便示例,这里是如何为每个元素分配一个单独的缓冲区:
char* dic[tam];
for (int i = 0; i < tam; i++) {
// Allocate 32 bytes per element.
// (This value can be decided at runtime, if you want.)
dic[tam] = malloc(32);
}
但是由于这使用malloc
,您需要确保在返回之前清理该内存以避免内存泄漏。例如,在你的例程结束时:
for (int i = 0; i < tam; i++) {
// de-allocate the buffer we allocated earlier
free(dic[tam]);
}
(这种在循环中多次调用malloc
的方法也可能导致内存碎片,但这是一个高级主题,不值得为小程序担心。)