基础知识
char e[] = "question"
是一个包含 9 个字符的char
类型数组
char* pe
是一个 char*
类型的指针
当对数组名e
进行取地址操作时(即&e
),会得到一个char(*)[9]
的数组指针
当把这个数组指针(char(*)[9]
)赋值给 char*
类型的单个字符指针时,由于类型不匹配会出现报错
正确写法应该是将数组名 e
赋值给 char*pe
,即 char* pe = e;
- 代码:
#include <iostream>
using namespace std;
int main(){
char e[] = "question";
char* pe = &e;
cout << pe << endl;
return 0;
}
- 运行:
报错,报错类型为类型不匹配 - 修改:
#include <iostream> using namespace std; int main(){ char e[] = "question"; char* pe = e; cout << pe << endl; return 0; }
- 运行:
question
因为cout
会对char*
类型做字符串处理
char 数组名、指针、数组首元素地址的关系
pe ≡ e ≡ &e[0]
,其中这三个输出的数值相同(均为question
),类型有差异。
pe
:是个 char*
指针,存着 e
数组开头的地址。
&e[0]
:明确取了 e
数组第一个元素的地址,类型也是 char*
。
e
(单独用作表达式):它本质上是 char[9]
数组。但当 cout
要打印它时,e
会自动变成 char*
(指向 e[0]
)。
当 cout
看到 pe
、e
、&e[0]
时,它们在 cout
眼里都暂时是 char*
,所以都按字符串来打印(输出结果:question)。但只有 e
的原始类型是数组。
- 代码:
#include <iostream> using namespace std; int main(){ char e[] = "question"; char* pe = e; cout << pe << endl; cout << e << endl; cout << &e[0] << endl; return 0; }
- 运行:
question
question
question
char*
的解引用与访问char数组首元素的不同方式
char*
类型指针名解引用、char
数组名解引用、数组首元素取地址并解引用、数组首元素,这些输出的结果和类型都相同(均为char
类型数值)
- 代码
#include <iostream> using namespace std; int main(){ char e[] = "question"; char* p = e; cout << *p << endl; cout << *e << endl; cout << e[0] << endl; cout << *(&e[0]) << endl; return 0; }
- 运行
q
q
q
q
sizeof()
运算符与数组大小
sizeof(e)
:返回整个数组的大小,char e[] = "question";
,返回的结果是 9
"question"
这个字符串有 8 个字母。但 C++ 会自动在字符串末尾加一个空字符 \0
来表示结束。所以,'q'
, 'u'
, 'e'
, 's'
, 't'
, 'i'
, 'o'
, 'n'
, '\0'
一共是 9 个字符,每个 char
占 1 个字节,所以总大小就是 9 字节。
- 代码:
#include <iostream>
using namespace std;
int main(){
char e[] = "question";
cout << sizeof(e) << endl;
return 0;
}
- 运行:
9
&
对数组名的作用
&e
:返回整个数组的地址(类型为 char(*)[9]
),意思是“指向一个包含 9 个 char
元素的数组的指针”。
- 代码:
#include <iostream> using namespace std; int main(){ char e[] = "question"; cout << &e << endl; return 0; }
- 运行:
输出该数组指针在内存中的地址,这是一个数组指针
char*
和 char(*)[9]
运算偏移的差异
char*
(如 pe
):*(pe + 1)
,移动 1
字节(指向 e[1]
)。
char(*)[9]
(如 &e
):&e + 1
,移动 9
字节(指向下一个 char[9]
数组)。
- 代码
#include <iostream> using namespace std; int main(){ char e[] = "question"; char* pe = e; cout << *pe << endl; cout << *(pe+1) << endl; cout << &e << endl; cout << &e+1 << endl; return 0; }
- 运行
q
u
数组指针e
的地址
数组指针e
偏移9个字节的地址
指针、数组名与首元素地址的关系
(void*)pe
输出的地址既是首元素 e[0]
的地址,也是数组 e
的起始地址(数值相同)。
cout
会对 char*
默认按字符串输出,所以需要强制转换为 void*
显示地址。其他指针类型(如 int*
)默认输出地址。
- 代码
#include <iostream> using namespace std; int main(){ char e[] = "question"; char* pe = e; cout << (void*)pe << endl; cout << (void*)e << endl; cout << (void*)&e[0] << endl; return 0; }
- 运行
三个相同的地址
地址值相同类型不同
地址数值相同,类型不同:pe
、&e[0]
、e
、&e
的地址值相同,但类型影响指针运算。
-
代码
#include <iostream> using namespace std; int main(){ char e[] = "question"; char* pe = e; cout << (void*)pe << endl; cout << (void*)e << endl; cout << (void*)&e[0] << endl; cout << &e << endl; return 0; }
-
运行
四个地址数值相同,但是指针类型不同前面三个 (
(void*)pe
,(void*)e
,(void*)&e[0]
) 都是void*
类型。&e
的类型是char(*)[9]
。
记忆技巧
数组名隐式转换指向数组首元素地址的指针:除了 sizeof
和 &
,数组名都是指向数组首元素地址的指针(存储的是首元素地址)。
cout对char*
特殊待遇:cout
对char*
按字符串处理,其他指针按地址处理。
地址数值相同,类型不同:数组首元素、数组名取地址、数组名的地址值相同,但指针类型不同,会影响指针运算。