在以下代码中:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
char** tab;
int n;
}slist;
void print(slist* p);
void add(slist* p, const char* s);
void add(slist* p, const char* s)
{
if(p->n==0)
{
p->tab=(char**)malloc(sizeof(char**));
}
strcpy(p->tab[p->n],s);
p->n=p->n+1;
}
void print(slist* p)
{
int i;
printf("[");
for(i=0;i<p->n;i++)
printf(" %s",p->tab[i]);
printf(" ]");
}
int main()
{
char s1[25] = "Picsou";
char s2[25] = "Flairsou";
slist* p = (slist*)malloc(sizeof(slist));
p->n=0;
p->tab=NULL;
add(p,s1);
add(p,s2);
print(p);
return 0;
}
函数add()
不起作用,但如果我将其更改为:
void add(slist* p, const char* s)
{
if(p->n==0)
{
p->tab=(char**)malloc(sizeof(char**));
}
p->tab[p->n]=s;
p->n=p->n+1;
}
它似乎运行得很好。在第一种情况下,输出仅为" ["
;在第二种情况下,它应该是:CCD_ 3。我不明白为什么。我也试过这个:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
char** tab;
int n;
}slist;
void print(slist* p);
void add(slist* p, const char* s);
void print(slist* p)
{
int i;
printf("[");
for(i=0;i<p->n;i++)
printf(" %s",p->tab[i]);
printf(" ]");
}
void add(slist* p, const char* s)
{
slist* tmp = (slist*)malloc(sizeof(slist));
tmp->tab=(char**)malloc(sizeof(char*)*(p->n+1));
int i;
for(i=0;i<p->n;i++)
tmp->tab[i]=(char*)malloc(sizeof(char));
strcpy(tmp->tab[p->n],s);
tmp->n=p->n+1;
p = tmp;
}
int main()
{
char* s1 = "Picsou";
char* s2 = "Flairsou";
slist* p = (slist*)malloc(sizeof(slist));
p->n=0;
p->tab=NULL;
add(p,s1);
add(p,s2);
print(p);
return 0;
}
这里有很多错误,这对于刚接触指针的人来说很常见。从哪里开始。。。我将按照代码中出现的顺序进行操作。
-
这不是一个"列表">
这是一个数组。。。有点。如果你对C程序员说"列表",他们会认为你指的是链表。
-
数组分配不正确
if(p->n==0) { p->tab=(char**)malloc(sizeof(char**)); }
这里已经分配了足够的内存来存储一个指针。第二次调用
add
时,您将访问末尾的内存。您还错误地强制转换了结果(在C中,您没有强制转换malloc
的返回值)。此外,您还向读取器提供了令人困惑的信息,因为您打算分配一个数组,该数组将包含类型为char*
、NOTchar**
的元素。您必须允许阵列在需要时动态扩展(现在不适合您的能力,可能几天后再尝试),或者设置最大大小。让我们这样做吧。
const int MAX_SIZE = 100; if( p->n==0 ) { p->tab = malloc( MAX_SIZE * sizeof(char*) ); } else if( p->n == MAX_SIZE ) { printf( "Maximum size exceeded!n" ); return; }
如果您愿意,可以使用
calloc
而不是malloc
。分配后,它将对块进行零初始化:calloc( MAX_SIZE, sizeof(char*) )
-
复制到未初始化的指针
strcpy(p->tab[p->n],s);
您为
tab
分配了内存,但没有分配其元素所指向的内存,并且在这里您有未定义的行为(很可能导致分段错误,但可以执行任何操作)。请确保您有一个有效的指针,并且它所指向的位置有足够的存储空间供您复制到其中的数据使用:
p->tab[p->n] = malloc( strlen(s) + 1 ); strcpy( p->tab[p->n], s );
-
存储可能无效的指针
您的"效果非常好"的替代方案使用:
p->tab[p->n]=s;
然而,这之所以有效,唯一的原因是这些指针在您使用"列表"的整个时间内都保持有效(但实际上,由于我在数字2中强调的原因,程序无法"工作"。
有时,我们希望程序中有这种行为,并将数据结构设计为索引它们不拥有的指针。但更常见的情况是,尤其是对于初学者来说,最好是复制数据(而不是简单地复制指针)。因此,您将使用我在上面第3条中建议的方法。
-
无可奉告
下面的代码有很多错误,我不打算把它拆开或解释它们。
void add(slist* p, const char* s) { slist* tmp = (slist*)malloc(sizeof(slist)); tmp->tab=(char**)malloc(sizeof(char*)*(p->n+1)); int i; for(i=0;i<p->n;i++) tmp->tab[i]=(char*)malloc(sizeof(char)); strcpy(tmp->tab[p->n],s); tmp->n=p->n+1; p = tmp; }
但是,您似乎在尝试执行类似于
realloc
的操作。这是我在第2条中提到的选项,我说你可能还没有准备好。但无论如何都要仔细阅读:realloc