指针的用法
大家都应该知道, 指针是个什么玩意儿, 它就是用来存另一个变量的地址的。这玩意儿在程序中容易引起不易察觉的错误, 而且会给调试带来莫大的困难。 尽管如此,它现在依然存在着, 这就从另一方面说明了, 它的功能爆表。 在实现链式存储, 图, 树, 森林时, 大都要用指针。 不仅如此, 在访问多维数组,函数参数传递时, 也多用指针。下面给出指针的一些常用的用法代码。
/*指针的声明及一般用法*/
/*________________________________________________________________*/
//声明:
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;
}
以上现象出现的原因是, 引用必须初始化,而且一旦初始化,就不再改变!