22-结构中的字符数组和字符指针
14.7.6 结构中的字符数组和字符指针
到目前为止,我们在结构中都使用字符数组来存储字符串。是否可以使用指向 char 的指针来代替字符数组?例如,程序清单14.3中有如下声明:
#define LEN 20
struct names {
char first[LEN];
char last[LEN];
};
其中的结构声明是否可以这样写:
struct pnames {
char * first;
char * last;
};
当然可以,但是如果不理解这样做的含义,可能会有麻烦。考虑下面的代码:
struct names veep = {"Talia", "Summers"};
struct pnames treas = {"Brad", "Fallingjaw"};
printf("%s and %s\n", veep.first, treas.first);
以上代码都没问题,也能正常运行,但是思考一下字符串被存储在何处。对于 struct names 类型的结构变量 veep ,以上字符串都存储在结构内部,结构总共要分配40字节存储姓名。然而,对于 struct pnames 类型的结构变量 treas ,以上字符串存储在编译器存储常量的地方。结构本身只存储了两个地址,在我们的系统中共占16字节。尤其是, struct pnames 结构不用为字符串分配任何存储空间。它使用的是存储在别处的字符串(如,字符串常量或数组中的字符串)。简而言之,在 pnames 结构变量中的指针应该只用来在程序中管理那些已分配和在别处分配的字符串。
我们看看这种限制在什么情况下出问题。考虑下面的代码:
struct names accountant;
struct pnames attorney;
puts("Enter the last name of your accountant:");
scanf("%s", accountant.last);
puts("Enter the last name of your attorney:");
scanf("%s", attorney.last); /* 这里有一个潜在的危险 */
就语法而言,这段代码没问题。但是,用户的输入存储到哪里去了?对于会计师(accountant),他的名存储在 accountant 结构变量的 last 成员中,该结构中有一个存储字符串的数组。对于律师(attorney), scanf() 把字符串放到 attorney.last 表示的地址上。由于这是未经初始化的变量,地址可以是任何值,因此程序可以把名放在任何地方。如果走运的话,程序不会出问题,至少暂时不会出问题,否则这一操作会导致程序崩溃。实际上,如果程序能正常运行并不是好事,因为这意味着一个未被觉察的危险潜伏在程序中。
因此,如果要用结构存储字符串,用字符数组作为成员比较简单。用指向 char 的指针也行,但是误用会导致严重的问题。