在C中存储char*数组



我正在尝试创建和存储一个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的方法也可能导致内存碎片,但这是一个高级主题,不值得为小程序担心。)

最新更新