大家都应该知道, 指针是个什么玩意儿, 它就是用来存另一个变量的地址的。这玩意儿在程序中容易引起不易察觉的错误, 而且会给调试带来莫大的困难。 尽管如此,它现在依然存在着, 这就从另一方面说明了, 它的功能爆表。 在实现链式存储, 图, 树, 森林时, 大都要用指针。 不仅如此, 在访问多维数组,函数参数传递时, 也多用指针。下面给出指针的一些常用的用法代码。
/*指针的声明及一般用法*/ /*________________________________________________________________*/ //声明: int a; int *p=&a; int a; int *p; p=&a; #include<stdio.h> int main() { int a, b; int *ipointer1, *ipointer2; scanf("%d%d", &a, &b); ipointer1 = &a; ipointer2 = &b; printf("The number is:%d %d\n", *ipointer1, *pointer2); } #include<stdio.h> int main() { int *p, q; p=&q; scanf("%d", p);//另类写法。 printf("%d\n", q); return 0; } //&*和*&的区别, &和*的优先级相同。运算顺序从左向右。 #include<stdio.h> int main() { int i; int *p; scanf("%d", &i); p=&i; printf("%d\n", *&i); printf("%d\n", i); printf("%d\n", *p); printf("%d\n", &*p); return 0; } //指针的自增自减。 #include<stdio.h> int main() { int i; int *p;//将变量i的地址赋给指针变量。 scanf("%d", &i); p=&i; printf("%d\n", p); p++;//指针变量加1, 这里的加 1 并不代表一个字节与*p的类型有关。 printf("%d\n", p); return 0; } //一维数组与指针 int *p, a[10]; p=&a; int *p, a[10]; p=&a[0]; #include<stdio.h> int main() { int *p, *q, a[5], b[5], i; p=&a[0]; q=b;//数组名就代表地址。 for(i=0; i<5; i++) scanf("%d", &a[i]); for(i=0; i<5; i++) scanf("%d", &b[i]); for(i=0; i<5; i++) printf("%5d", *(p+i)); printf("\n"); for(i=0; i<5; i++) printf("%5d", *(q+i)); return 0; } #include<stdio.h> int main() { int *p, *q, a[5], b[5], i; p=&a[0]; q=b; for(i=0; i<5; i++) scanf("%d", p++); for(i=0; i<5; i++) scanf("%d", q++); p=a;//使指针变量p,q 重新指向数组起始位置。 q=b; for(i=0;i<5; i++) printf("%5d", *p++); printf("\n"); printf("%5d", *q++); return 0; } //二维数组与指针。 #include<stdio.h> int main() { int a[3][5], i, j; for(i=0; i<3; i++) { for(j=0; j<5; j++) scanf("%d", a[i]+j); } for(i=0; i<3; i++) { for(j=0; j<5; j++) printf("%5d", *(a[i]+j)); printf("\n"); } return 0; } // #include<stdio.h> int main() { int a[3][5], i, j, *p; p=a[0]; for(i=0; i<3; i++) { for(j=0; j<5; j++) scanf("%d", p++); } } p=a[0]; for(i=0; i<3; i++) { for(j=0; j<5; j++) printf("%5d", *p++); printf("\n"); } #include<stdio.h> int main() { int a[3][5], i, j, (*p)[5]; p=&a[0]; for(i=0; i<3; i++) //控制二维数组的行数。 for(j=0; j<5; j++) //控制二维数组的列数。 scanf("%d", (*(p+i))+j); //为二维数组中的元素赋值。 p=&a[1]; //*p为第一个元素的地址。 for(j=0; j<5; j++) printf("%5d", *((*p)+j));//输出二维数组中的元素。 printf("\n"); return 0; } #include<stdio.h> int main() { int a[3][5], i, j; for(i=0; i<3; i++) for(j=0; j<5; j++) scanf("%d", *(a+i)+j); for(j=0; j<5; j++) printf("%5d", *(*(a)+j)); printf("\n"); return 0; } // #include<stdio.h> int main() { char str1[]="you are beautiful", str2[30], *p1, *p2; p1 = str1; p2 = str2; while(*p1!='\0') { *p2 = *p1; p1++; p2++; } *p2='\0'; printf("Now the string2 is:\n"); puts(str2); return 0; }
上面的代码只是给出了,指针的一般用法。 如果你想比较深入的理解一下指针是什么鬼, 下面的文字也许对你有些帮助。
首先给出一个警告: 一定要在对指针应用解除引用运算符(*)之前, 将指针初始化为一个确定的, 适当的地址。 -----这是关于使用指针的金科玉律。
误用指针的原因:
在C++中创建指针时, 计算机只分配了用来存放地址的内存, 而没有分配用来存储指针所指向的数据的内存。 为数据提供空间是一个独立的步骤, 而忽略这一步骤, 就可能带啦灾难性的bug。
//错误代码, 请勿模仿。 int* p; *p = 5;
上面的 p 的确是一个指针, 但是并不知道它指向哪里去了? 上述代码没有将地址赋给 p 。 那么 5 放到了哪里去了呢?----------》 鬼知道 。 由于 p 指向的地方不知道在哪里。 (没准是你的程序中关键代码的地址) 。 如果是这样, 就可能会导致一些最隐匿, 最难以跟踪的bug。
空指针: C++确保空指针不会指向有效的数据, 因此它常被表示运算符或函数失败(如果成功, 它们将返回一个有用的指针)。
空指针的声明方法:
int *p1 = nullptr;
int *p2 = 0;
int *p3=NULL
//上述三种声明方式等价。
事实上, 数组名和指针是差不多的,编译器在编译数组时, 会把数组编译成指针的形式。
a[i] 会被编译成 *(a+i) //你知道的, 数组的首地址相当于指针, //而 i 的值是编译器会根据数组的类型 //而定的。 而一个指针变量, 如果让它指向一个数组首地址 也可以用数组的形式来访问数组元素。 int a[3]={1, 2, 10} int*p = a;//*p = &a[0] cout<<p[0]<<endl; cout<<p[1]<<endl;
当然, 数组名和指针还是有区别的。 区别一: 可以修改指针的值, 因为指针是指针变量。 但是数组名是常量, 不能更改!。 区别二: 对数组应用sizeof运算符得到的是数组的长度, 而对指针应用sizeof的得到的是指针的长度。
数组的地址:
其实对数组取地址时, 数组名也不会完全被解释为数组的地址。 数组名被解释为其第一个元素的地址, 而对数组名应用地址运算符时, 得到的是整个数组的地址:
int a[10]; cout<<a<<endl;//displays &a[0] cout<<&a<<endl;//displays address of whole array //从数值上说, 这两个地址相同, 但是从概念上说缺有区别 //&a[0] 是 一个4字节的内存地址(即:告诉计算机要4个字节)。 //&a 是一个40字节的内存地址(即:告诉计算机要40个字节的空间) //数组地址的这个特点为多维数组实现提供了方便。
void*指针:
void*是一种特殊的指针类型,可以存放任意对象的地址(如: int型, double型, char型, 函数形, 结构体型, 等)。一个void*指针存放着一个地址, 这一点和其他指针类型类似。 不同的是我们对该地址中到底是什么类型的对象并不了解。因此不能直接操作void*指针所指的对象。 但是可以比较它和别的指针的大小, 作为函数的输入输出, 或者赋值给另外一个void*。
指向指针的引用:
int i=42;
int *p; // p是一个int型的指针
int *&r = p; //r是一个对指针p的引用.
r=&i; //r引用了一个指针,因此给r赋值&i就是令p指向i。
*r = 0; //解引用r得到 i,也就是p指向的对象, 并将i的值改为0
下面是一个关于指针的程序的简单分析:
#include<cstdio> #include<iostream> using namespace std; int fun(int *data) { return (*data)++; } int main() { int data = 55; cout << fun(&data) << endl; cout << data <<endl; data = fun(&data); cout << data <<endl; return 0; }
本程序输出的是 55 56 56
是不是感到很神奇呢? 分析此程序可以知道 形参是指针类型的, 所以它是可以改变main()里的data的值的。 第一次调用fun()时, data=55, 然后返回 *data 给cout输出流(此时值为55) 相当于赋值给另一个变量了(这才是输出的值), 然后 *data+1 也即是: main()中的data+1, 此时data = 56. 所以第二次输出为56. 然后 是同样的 data = fun(&data) 这是关键的一句。 fun()函数返回 56, 然后 data+1 = 57 然后是 data = fun()的值, 由于fun()返回的值是56, 所以57被覆盖啦。因此第三次data输出 56. 建议上机调试此程序,以便更深入的理解。 提示: 不要在DEV C++里调试, 这个编译器的调试软件版本较老,调试此程序时可能有误!建议在 VS2010或更高版本上调试。
下面是关于一个指针的引用的示例:
#include<iostream> int main() { using namespace std; int rats = 101; int *pt = &rats; int &rodents = *pt; // 在声明的时候, 将rodents初始化为 *pt int bunnies = 50; // 使得rodents指向了 rats。而后不再随 pt = &bunnies; //*pt的改变而改变。 cout << "rats = "<< rats << endl; cout << "*pt = " << *pt << endl; cout << "rodents = " << rodents << endl; cout << "bunnies = " << bunnies << endl; cout << "rats's address = " << &rats << endl; cout << "rodents's address = " << &rodents << endl; cout << "*pt's address = " << pt << endl; return 0; }
以上现象出现的原因是, 引用必须初始化,而且一旦初始化,就不再改变!
来源:https://www.cnblogs.com/acm1314/p/4509141.html