我注意到char*
在C中的工作方式与所有其他指针在C中工作的方式之间存在一些差异。例如,一个差异是:当打印出char指针本身时,它会返回其值,直到终止为止:代码:
char* var = "Hello World";
printf("%s", var);
输出:
Hello World
但当对其他指针执行相同操作时,它会返回存储在内部的值的地址,如下所示:代码:
int var = 5;
int* pVar = &var;
printf("%d", pVar);
输出
//Random memory address
我还注意到,不能像这样直接声明不是char*
的指针:
int* var = 5;
有人能列出这些指针之间的所有差异吗?为什么会存在这些差异?感谢
让我们逐一研究您的每个问题。
打印
在您的第一个代码片段中,您展示了printf
能够打印字符串。当然它印了一串。你给了它一个%s
,它应该是一个字符串。但首先,什么是弦?为了解释这一点,我们需要了解数组和字符。
什么是字符串
首先,什么是char
?char
是一个奇异字符(或8位数字,但就我们的目的而言,它是一个字符)。字符可以是字母(a
、b
、c
)m或任何其他符号(?
、!
、.
,数字,还有一些控制字符)。通常,如果你只需要一个字符,你会这样声明:
char letter_a = 'a';
那么什么是数组呢?数组是一组相邻的值。考虑以下代码:
int int_array[] = int[50];
int_array[0] = 1;
int_array[1] = 2;
...
在本例中,什么是int_array
?答案似乎显而易见。这是一个数组。但它的意义远不止于此。如果我们这样做呢?
printf("%dn", *int_array);
它打印出1
。为什么?因为int_array实际上只是指向数组第一个元素的指针。
那么,我为什么要谈论数组呢?因为字符串只是一个字符数组。当您运行char* string = "Hello!"
时,您只需创建一个如下所示的数组:['H', 'e', 'l', 'l', 'o', '!', ' ']
。一旦字符串到达空符号(' '
),C就知道该字符串已经结束。
在第一个代码段中,var是一个指向字母"H"的指针,print语句一直打印字符,直到它达到null。
第二个片段呢
%d
不像%s
那样取消引用变量。它只是将数字打印为带符号整数。本例中的整数是整数的内存地址。
为什么不能分配指针
你可以。你会得到一个警告,它可能会导致分段错误,但你可以尝试一下。我用clang编译了你的代码示例,这就是我得到的:
test.c:1:1: warning: return type of 'main' is not 'int' [-Wmain-return-type]
void main() {
^
test.c:1:1: note: change return type to 'int'
void main() {
^~~~
int
test.c:2:7: warning: incompatible integer to pointer conversion initializing 'int *' with an expression of type 'int' [-Wint-conversion]
int* var = 5;
^ ~
2 warnings generated.
不过我不敢试着跑。基本上,您刚才所做的是尝试访问内存中的第五个位置,这很可能是一些操作系统的东西。你无法访问
为什么它对字符串有效
因为它没有指向特定的位置。它指向C为您制作的字符串的位置。你的代码大致相当于:
char h = 'H';
char e = 'e';
...
char* var = &h;
char*
与其他指针类型没有什么不同。它只指向一个字符。C中的大多数字符串操作都将其视为指向一系列字符,并读取它,直到找到空终止符。
指向int
的指针可以表示指向一个int
值的指针,也可以表示指向int序列开头的指针,或者可以不指向任何内容,这是一个空指针。指针没有长度,在读取其他索引之前,您需要知道某个指针的长度。C字符串使用空终止符来表示结束。
您不能执行int *var = 5
,因为这没有意义(实际上,如果您像int *var = (int*)5
一样强制转换它,那么如果您想访问某个映射到模糊系统上的确切地址0x00000005的I/O寄存器,这可能是有意义的)。指针的值包含一个内存地址。相反,您可以先生成一个整数值,比如int myInt = 5;
,然后是int *myPointer = &myInt;
。您可以通过间接运算符*
访问5。
指针有很多用途,尤其是在将数据传递给不同方法时。假设您有一个500字节的数据结构。您可以将所有这些数据复制到各处,也可以只传递一个指针值,这样所有数据都可以在适当的位置进行操作。指针也是基本的逐引用传递功能,在从函数返回多个值时尤其有用。在C API中,您通常会看到接受单个int作为函数参数的指针,这些指针是函数的指定输出。
printf的%s
格式符号正在寻找一个指向字符串的指针,这是一个普通的char*指针,但在null终止符之前,它希望它是多个字符。%d
格式的符号要求一个int值,因此当您将指针传递到其中时,它会将其视为int值——请注意,这是未定义的行为。%p
用于读取存储器地址(指针),而不是%d
。
每种指针类型之间的主要区别是用于索引运算的每个存储单元的大小。对char指针进行索引,例如chars[10]
将返回第11个char
,在大多数现代系统中,char是1个字节,因此它将返回第10个字节。为int*
指针编制索引使用更宽的步长,通常每个索引4个字节,因此myInts[10]将返回指针地址的第11个int值,但此处的每个内存步长为4个字节。有时,为了方便在索引数组时测量字节,人们只转换为字节大小的指针,然后再转换回他们想要读取的类型。