对指针加1,加的是指针类型的字节数。
例如:
int*a[5];
a+1;
这个时候,由于int是4字节,因此实际上是地址的位置加4,也就是向右移动一个int字节的宽度。
减一刚好相反,是向左。
而*a+1; 是指针a所指的地址的变量+1,但是指针位置是不变的。
#include<iostream> int main() { using namespace std; int *a; int b[4] = { 1,2,3,4 }; //声明数组b,数值分别为1~10 cout << "int b[4] = { 1,2,3,4 }" << endl << endl; cout << "b[0]= " << b[0] << endl; //输出数组b的第一个元素 //输出数组b的地址 b 和 &b 时,二者输出是一样的 cout << endl; a = &b[0]; //将指针和数组的第一个元素的地址对齐 cout << "a = &b[0];" << endl; cout << "*a = " << *a << endl; //输出指针a的变量 cout << "指针a的地址为:" << a << endl; //输出指针a的值 a = a + 1; //指针a+1 cout << "a = a+1;\n*a = " << *a << endl; //指针a+1后,指针a的变量 cout << "指针a的地址为:" << a << endl; //输出指针a的值 cout << "*(a+1) = " << *(a + 1) << endl; //指针a+1后,输出(a+1)的变量,注意,这里只是输出a+1,但并没有a=a+1 cout << "*a = " << *a << endl; //说明,没有a=a+1时,指针a的位置是不变的。输出的结果依然是2,也是数组b的第二个元素 cout << "指针a的地址为:" << a << endl; //输出指针a的值 a = a - 1; //指针a-1 cout << endl << "a = a - 1;" << endl; cout << "*a = " << *a << endl; //指针a+1后再次a-1,指针a的变量 cout << "指针a的地址为:" << a << endl; //输出指针a的值 cout << endl << "以下对数组b的地址 b 和 &b 进行操作" << endl; cout << "数组b的地址,\nb = " << b << endl; //输出数组b的地址 cout << "&b = " << &b << endl; //&b也是数组b的地址 cout << "b + 1 = " << b + 1 << endl; //b+1是加的数组中一个元素的宽度,地址偏移数组一个元素的类型(int)的距离 cout << "&b + 1 = " << &b + 1 << endl; //&b+1是地址偏离了整个数组长度的宽度的距离 system("pause"); return 0; }
输出:
int b[4] = { 1,2,3,4 } b[0]= 1 a = &b[0]; *a = 1 指针a的地址为:0040FBA8 a = a+1; *a = 2 指针a的地址为:0040FBAC *(a+1) = 3 *a = 2 指针a的地址为:0040FBAC a = a - 1; *a = 1 指针a的地址为:0040FBA8 以下对数组b的地址 b 和 &b 进行操作 数组b的地址, b = 0040FBA8 &b = 0040FBA8 b + 1 = 0040FBAC &b + 1 = 0040FBB8 请按任意键继续. . .
备注:
①int a[4];后,a是一个指针,是4字节(int)的指针;而&a是面向数组a全部元素的一个指针(4字节*4个元素);
指针算数:
两个指针可以相减,如代码:
#include<iostream> int main() { using namespace std; int a[10]; int *b, *c; b = &a[0]; c = &a[5]; cout << "指针c为&a[5],指针b为&a[0]。指针c-指针b: c - b = " << c - b << endl; system("pause"); return 0; }
输出结果为:
5
结论:
①指针相减的结果,相当于两个元素之间指针需要偏移的距离(5个int)。
对指针解除引用:
对指针解除引用,实际上就是显示指针(所指向)的值,运算符是*。
例如int *p; p是指针,*p就是对指针p解除引用。
另外一种对指针解除引用的方法就是数组表示法,即p[0],[0]表示指针当前地址的值。
不要对没有被初始化的指针解除引用。
delete指针:
指针初始化后可以delete 指针。例如
int *a = new int;
delete a;
这样是ok的。也可以给指针赋值后,删除指针。
数组和指针:
上代码:
#include<iostream> #include<cstring> int main() { using namespace std; char *a, b[10] = { 'a','b' }; //声明指针a。再声明数组b为字符串ab a = b; //将字符串b赋值给指针a cout <<"a = "<< a << endl; //指针a输出字符串 cout <<"b = "<< b << endl; //数组b输出字符串 cout <<"&a= "<< &a << endl; //输出指针a的地址,这是储存指针a的内存地址 cout <<"&b[0] ="<< &b[0] << endl; //这行无法输出数组b的地址,不加&输出的是数组b的第一个元素, //但加了&,cout会从第一个字符输出到空字符为止——(但是不知道为什么) cout <<"&b= "<< &b << endl; //输出数组b的地址,注意,和指针a的地址是不同的 cout << (int*)a << endl; //只有改为(int*)a才能输出指针a所输出的地址,如果是(char*)a将依然输出字符组 cout << endl; a = "ffff"; cout << "a = " << a << endl; //指针a输出字符串 cout << "b = " << b << endl; //数组b输出字符串 cout << "&a= " << &a << endl; //输出指针a的地址,这是储存指针a的内存地址 cout << "&b[0] =" << &b[0] << endl; //这行无法输出数组b的地址,不加&输出的是数组b的第一个元素, //但加了&,cout会从第一个字符输出到空字符为止——(但是不知道为什么) cout << "&b= " << &b << endl; //输出数组b的地址,注意,和指针a的地址是不同的 cout << endl; int *c, d; d = 123; c = &d; cout <<"c = "<< c << endl; cout <<"d = "<< d << endl; cout <<"&c= "<< &c << endl; cout <<"&d= "<< &d << endl; cout << endl << "*c = 5" << endl; *c = 5; cout << "c = " << c << endl; cout << "d = " << d << endl; cout << "&c= " << &c << endl; cout << "&d= " << &d << endl; cout << endl; system("pause"); return 0; }
输出:
a = ab b = ab &a= 0029F790 &b[0] =ab &b= 0029F77C 0029F77C a = ffff b = ab &a= 0029F790 &b[0] =ab &b= 0029F77C c = 0029F764 d = 123 &c= 0029F770 &d= 0029F764 *c = 5 c = 0029F764 d = 5 &c= 0029F770 &d= 0029F764 请按任意键继续. . .
①当给指针赋值数组的时候,如果输出指针,那么实际输出的是数组(但数组如果有数字可能乱码,字符串不会)
②如果要输出地址,则需要给数组前面加&,或者给指针前面加&,才能输出地址。但两个输出的地址不同,&a是储存指针a的地址,&b是数组b的地址。a由于输出的是字符串,所以无法输出地址。只有加了(int*)或者其他(类型名*)才能将其强制转换为内存地址,若是(char*)将依然输出字符串
③储存指针的内存地址和指针所表示的内存地址,是不同的,前者的内存地址储存的值 是 指针的内存地址。
④当指针表示字符串的时候,改变指针的值,只改变指针的值,不像指针表示内存地址时,将影响指针指向内存地址的值。具体见a="ffff";后的语句。
⑤字符串/数组的第一个元素的内存地址,将表示数组的内存地址。但不能用(int*)数组名[0]这样的,把(int*)改成(char*)也不行,会输出地址,但不是预期想要的地址。至于为什么,不知道。只能用(int*)数组名,或者&数组名,才能显示数组的地址。
⑥char*a;是指针,当被赋值为字符串时,输出a的时候输出的就是字符串。
前者:(一般是char*指针情况下)
char a[] = "abc"; char *b; b = a; cout << a << endl;
输出的为:abc
后者:
string a = "abc"; string *b; b = &a; cout << b << endl;
输出的为:0043FDFC是一个地址。
指针和字符串:
数组和指针的特殊关系,是可以扩展到C-风格的字符串的。
例如:
char a[10] = "abc"; cout << a << endl;
其中在第二行语句中,字符串a实际上是被cout认为是字符串a的地址,而cout的效果,实际上是读取内存地址,然后按顺序输出字符,直到遇见空字符(\0)为止,另外,空格\回车等并非空字符。——这也是为什么字符串最后要是空字符的原因。
当使用指针的时候,如在上面代码后面加上这两句代码:
char *b; b = a; <span style="white-space:pre"> </span>cout << b << endl;
b是一个指针,又因为a实际上也是一个地址,因此a才能被赋值给b,此时b被认为是字符串a的地址。
然而,当cout遇见b的时候,因为cout发现两件事①b是地址②b是char类型的指针。于是,输出的是字符串,至于原因,要看下一行。
在cout和C++的多数表达式中,char 数组名、char 指针以及用括号引起的字符串常量(比如"abc"),都被解释为字符串的第一个字符的地址。而输出的是字符串。只有当在之前加上 & 之后,才能显示出内存地址。
比较典型的如以下代码:
#include<iostream> #include<cstring> int main() { using namespace std; char animal[20] = "bear"; //声明字符串animale为"bear" const char * bird = "wren"; //常量字符串bird为wren char * ps; //对于char*类型的指针,cout是根据指针地址输出字符串,而不像比如int*类型或者string*类型的指针那样输出地址 cout << animal << " and " << bird << endl; //输出字符串animal和常量字符串bird cout << "输入一种动物:"; cin >> animal; //让用户输入字符串animal,覆写之前的bear ps = animal; //由于ps是一个可变指针,animal是字符串,所以ps是字符串 cout << "ps = : " << ps << "!\n"; //输出ps(ps是字符串) cout << "在使用strcpy():之前——strcpy(目标字符串,源字符串)是将字符串从一个位置复制到另外一个位置\n"; cout << animal << " at " << (int*)animal << endl; //第一个animal是输出字符串,第二个加了(int*)是强制转换,输出的是指针 cout << ps << " at " << (int*)ps << endl; //第一个ps是指针,第二个ps加(int*)是输出储存指针的指针 ps = new char[strlen(animal) +1]; //new 一个char字符串,宽度是animal宽度+1 //strcpy(ps, animal); //这行命令编译出错,正常来说,应该是将animal的字符串复制到ps新的内存地址处 ps = "ab"; //用自行赋值替代 cout << "在使用strcpy()之后\n"; cout << animal << " at " << (int*)animal << endl; //animal的值和地址不变 cout << ps << " at " << (int*)ps << endl; //ps获得新值和新的地址 //delete[] ps; 这行代码应该是要删除指针ps,但实际上出错了,不知道为什么? system("pause"); return 0; }
①在以上这个代码之中,对于char*类型的指针,cout输出的为字符串。只有之前加上 & 之后,输出的才不是字符串,而是地址——只不过是储存指针的地址,而非指针指向的地址。
②对于字符串而言,cout输出的是字符串(直到遇见空字符\0)为止。只有在字符串(数组)之前加上&,显示的才是字符串的地址。
③对于int*类型,或者其他类似的指针来说,cout输出的指针是地址,但char*类型的指针例外——似乎也只有char*类型的例外。
④在vs2015里面,strcpy(ps,animal)这行语句会提示不安全。——但是我也不知道怎么改。
⑤因为ps是指针,因此才能ps=new char[],这是给指针a一个新的内存地址,这个时候,指针a的地址为该地址,但是&a为储存指针a的内存地址,只有用强制转换如(int*)a,才能得出新地址是在哪里。
⑥char*,数组,字符串,以及字符串常量(比如char a[5]="abc";这样。字符串abc为字符串常量,被储存在内存的某个专门的区域),cout都理解为内存地址,输出的是字符串,而不是地址。只有加了&后,才根据具体情况输出地址,但不一定是字符串所在地址——比如指针指向该字符串,指针加&输出的是储存该指针的内存地址(而非指针指向的内存地址)。
⑦因为char*类型,一般被cout认为是地址但输出的字符串,因此如果想输出地址的话,需要用强制转换,比如转换为(int*)类型的指针,才能输出地址。
⑧因为某个不知道的原因,删除指针delete[]ps;时,提示出错了,不知道为什么。
⑨假如char*a="abc"; cout <<a<<endl;这个时候,指针a指向了字符串abc所在的内存地址,输出的是abc。假如之后加上代码a="def";cout<<a<<endl;这个时候,改变a并没有将abc所在内存地址的值改变,而是改变了指针a指向的内存地址,为字符串"def"所在的内存地址。
想改变char *a所指向内存地址的值的话,需要通过*a='d';*(a+1)='e';*(a+2)='f';
这样,把字符串“abc”所在内存地址的值,改为字符串def。
或者通过
cin>>a;
这样,将用户输入的值,直接覆写到指针a所指向内存地址的之上。
但是不能通过比如*a="def";这种形式,企图一次写多个字符到字符串之中。
不过或许可以通过strncpy(a,"字符串",字符串长度);这样的形式将字符串写入,但问题在于,我的vs2015提示这是不安全的,无法编译。