前言指针与地址指针使用
声明指针
指针变量的创建细节 取地址符初始化赋值
指针的整形赋值 算术运算指针解引用(取值运算符)
区分指针类型与解引用 动态内存分配
动态数组动态内存释放 数组名与指针指针数组与数组指针
指针数组数组指针对数组取地址 指针与字符串 后记
前言指针是C,C++与其它语言的一大区别,也是C++程序设计里的难点。
本篇学习C++指针的基本用法。
指针与地址地址是内存空间的位置,指针是保存地址的特殊数据类型。
广义的说,指针就是地址,指针变量用于存储地址。
狭义的说,地址就是内存空间的编号,而指针有具体的存储数据类型(比如int *p;),因此指针不完全是地址。
指针使用 声明指针声明指针必须说明是指向什么数据类型的指针(这样才能确定数据在内存空间的使用量):
int *p_int; double *p_double;指针变量的创建细节
声明指针时,计算机会给指针变量分配内存空间用于存储地址,但是不会给指针指向的数据分配内存空间,下面的使用方法将报错:
int *p_n; *p_n = 0;
声明指针p_n时,系统给p_n分配了内存空间,其地址为addr1,存储的是p_n;但系统没有在p_n存储的地址addr2分配空间,因此addr2是个未定值,系统不知道把0放到哪个地址上,因而报错。
取地址符&被用于取得变量的地址:
int variable = 0; std::cout << &variable;初始化
可以在声明指针时初始化指针:
int a = 2; int *p_a = &a;
指针p_a被初始化,获得a的地址,指向变量a。
赋值可以通过赋值运算符,把地址赋给指针:
int b = 2; int *p_b; p_b = &b;指针的整形赋值
计算机将指针当作整数处理,但指针和整形是两种不同的数据类型,指针没有乘除计算。因此不能简单的把整形赋给指针,必须使用强制类型转换:
int *p_s = (int *) 0x10000000;算术运算
指针有加减法:
int *pp = new int; cout << (pp + 1); // pp地址后的一个位置
比如pp=0x10000000,pp + 1 = 0x10000004,即地址增加了4个字节的长度(int类型长度)。
在数组中的两个元素的指针相减,能得到两个元素的间隔。
指针解引用(取值运算符)*除了是指针类型名,还用于取得指针指向的数据,也叫指针的解引用:
double c = 5.2f; double *p_c = &c; std::cout << *p_c;区分指针类型与解引用
在声明和初始化中,*表示声明的是指针类型。
在指针变量被声明和赋值后,*表示的是指针解引用。
short d = 1; short *p_d = &d; // 声明指针类型 *p_d; // 解引用动态内存分配
定义变量是一种分配内存空间的方法(自动变量,栈空间):
int e = 5; // 在栈空间中分配内存 int *p_e = &e;
使用new是另一种分配内存空间的方法(动态存储,堆空间):
int *p_f = new int;
new TypeName在内存空间中找到一块满足TypeName类型的块,返回内存空间的地址。
动态数组new TypeName []用于创建动态数组:
int *p_vec = new int [10];
``delete []````用于释放动态数组空间:
delete [] p_vec;动态内存释放
动态分配的内存空间,如果不需要再使用时,要及时通过delete释放,new,delete要成对使用。否则容易出现内存泄漏memory leak。
delete不会把指针删除,而是释放指针指向的内存空间。空间释放后,最好把指针置空:
int *p_g = new int; delete p_g; p_g = nullptr;
delete不能释放栈空间上的内存,但是可以delete空指针。
也不能对同一个指针释放两次,会报double free的错误。
C++11推出了智能指针,能够降低内存泄漏的风险。
数组名与指针C++中,数组和指针基本是等价的,数组名表示数组第1个元素的地址。区别在于,数组名的值是不能改变的,但指针变量的值是可以改变的。通过指针访问数组元素:
p_vec[1] = 1; // 使数组第2个元素为1; *(p_vec + 1) = 1; // equal;
需要注意,对数组使用sizeof得到数组长度,对一个指向数组的指针应用sizeof得到指针长度。
指针数组与数组指针 指针数组指针数组,变量名表示一个数组,也就是数组中的每个元素都是一个指针,:
int* vec_p[5];
上面这个声明中,[]比*的优先级高,因此vec_p[5]是一个数组,而int*指定了数组类型为整形指针。
指针数组常用于字符串数组:
char* vec_string[2] {"Hello, ", "World!"};数组指针
数组指针,变量名表示一个指针,指向整个数组:
int (*p_vec)[10];
上面这个声明中,首先声明了p_vec是一个指针,指向一个10元素整形数组。此时,p_vec + 1是p_vec地址后40个字节的位置。
数组指针常用于多维数组(比如OpenCV中Mat数据读取),举个二维数组的例子:
ushort pixel[5][10]; ushort (*p_pixel)[10] = pixel; (*(p_pixel + 2))[4] = 3 // 设置第3行,第5列数据的值为3 std::cout << (*(p_pixel + 2))[4]; // 输出第3行,第5列数据的值 p_pixel[2][4] = 3; // equal对数组取地址
数组名表示数组首元素的地址,对数组取地址也会获得数组的地址,但二者的含义是不一样的:
int vec[5] {0, 1, 2, 3, 4}; std::cout << vec << "n"; std::cout << &vec << "n"; std::cout << (vec + 1) << "n"; std::cout << (&vec + 1) << "n";
结果:
0x7ffe8742ebd0 0x7ffe8742ebd0 0x7ffe8742ebd4 0x7ffe8742ebe4
取数组的地址时,返回的是整个数组的地址,也就是包含5个int元素的地址,&vec + 1的地址为数组首元素地址 + 5 * 4。
而数组名,就是数组首元素的地址,vec + 1的地址为数组首元素地址 + 4。
指针与字符串C++中,char数组名,char指针,字符串常量都被解释为字符串中第一个字符的地址。
给cout提供一个字符的地址,将从该字符开始打印,直到遇到空字符为止,比如:
char str[6] = "hello"; std::cout << str;
结果:
hello
cout虽然接收的是char地址,但输出是字符串。如果要打印字符串的地址,则必须使用强制类型转换:
std::cout << (int *) str;
注:发现可以使用字符串常量的列表初始化字符串数组:
char str[6] {"hello"};后记
本篇记录了C++中指针的基本使用,以及指针和数组,字符串的关系,下一篇将学习枚举和结构体。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)