为什么char必须是指针而不是char类型?

3
#include <stdio.h>

typedef struct {
    char * name;
    int age;
} person;

int main() {
    person john;

    /* testing code */
    john.name = "John";
    john.age = 27;
    printf("%s is %d years old.", john.name, john.age);
}

这是一段运行良好的代码,我只有一个小问题。在结构体部分,当我删除name前面的*后,这段代码就不再工作了,但无论age的类型是int还是指针,它都能正常工作。那么,有人能告诉我为什么name必须是指针,而不仅仅是char类型吗?

4个回答

3

char类型是字符类型,可以容纳一个字符。C语言中没有string类型,相反,在C语言中,字符串是以'\0'(空字符)结尾的char数组 - 即以空字符为结尾的字符串(null terminated strings)。

因此,要使用字符串,您需要指向包含许多字符的内存的指针。那么为什么在int中使用或不使用*都可以工作呢?这是因为我们可以将年龄设置为int,也可以将其设置为存储年龄的内存的指针。两种方法都很好。但我们无法将字符串存储在一个字符中。


1
这与printf函数中的格式说明符有关。 %s 试图输出字符串(读取一部分内存),%d 将gets中的所有内容解释为整数,因此即使是指针也可以工作,但是你不应该这样做,这是未定义的行为。
我建议您阅读一些关于C语言的好书,以便更好地掌握这些知识。这里有一个好书单 The Definitive C Book Guide and List

1

但是无论年龄类型是int还是指针,它总是可以正常工作。

这是未定义的行为。

具体来说,双引号包含的字符串(如上所示)是一个字符串字面量,当用作初始化器时,它基本上会给您一个指向字面量开头的指针,因此需要使用指针变量来存储name。另一方面,初始化器27是一个整数字面量(整数常量),它需要存储到int变量中,而不是int *。如果您使用27来初始化int *并使用它,它会工作(更确切地说,似乎会工作),因为那样会在以后尝试使用无效内存位置时触发未定义行为

顺便说一下,如果您尝试类似以下的操作

typedef struct {
    char * name;
    int *age;
} person;

然后

john.age = 27;  //incompatible assigment

编译器会警告您整数转换为指针的错误。

0

char *name: name 是指向类型为char的指针。当你将它指向"John"时,编译器会将John\0即5个字符存储到某个内存中,并返回该内存的起始地址。因此,当你使用%s(字符串格式说明符)进行读取时,name变量会返回整个字符串,直到遇到\0为止。

char name:这里的name只是一个字符,占用1个字节的内存。因此,你不能存储超过一个字符的任何内容。而且,当你尝试读取时,应该始终只读取一个字符(%c),因为尝试读取更多内容会导致访问未分配给你的内存区域,从而引发未定义行为

int ageage被分配了4个字节的内存,因此你可以将一个整数存储到这段内存中并进行读取,例如:printf("%d", age);

int *ageage是一个指向int类型的指针,它存储某个内存的地址。与字符串不同,你不能使用地址来读取整数(松散地说,为了避免复杂性)。你必须对它进行解引用。所以首先,你需要分配一些内存,将任何整数存储到其中并将该内存的地址返回给age。否则,如果你不想分配内存,你可以使用编译器的帮助,通过像这样为age赋值:*age = 27。在这种情况下,编译器将把27存储到一些随机内存中,并返回地址给age,可以使用*age进行解引用,如printf ("%d", *age);


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接