指针简介

include
#include
int main(void)
{

//与指针相关的运算符

  1. //地址运算符 : &<br /> //一般注解 :<br /> //后跟一个变量名时, & 给出该变量的地址。<br /> //示例 :<br /> //&nurse表示变量nurse的地址。<br /> //<br /> //地址运算符 : *<br /> //一般注解 :<br /> //后跟一个指针名或地址时, * 给出储存在指针指向地址上的值。<br /> //示例 :<br /> //nurse = 22;<br /> //ptr = &nurse; //指向nurse的指针<br /> //val = *ptr;//把ptr指向的地址上的值赋给val<br /> //执行以上3条语句的最终结果是把22赋给val。<br />

//指针是什么

/*指针是一种数据类型,就像int, float, int是 装整型数据<br />    float是装浮点型数据,指针是装地址型数据,仅此而已。*/<br />    //声明写法 类型加*加变量名<br />    //int* p;  //声明了一个指针变量,p是一个变量<br />      //int表示p装的地址对应的空间的数据类型<br />      //*代表p是一个指针变量<br />      //p是指针的名字<br />    //指针就是装地址的变量,变量就要赋值,<br />    //即 使一定要装一块空间的地址,或者指向一块空间,才能被使用<br />    //就像int a;我们没有初始化,没有赋值,a就没有用,<br />    //啥也不能干.指针变量也同理,不装地址的情况下,啥都不干,也叫(野指针)

//指针的初始化

int a = 12; //定义一个变量a<br />    int* p = &a; //申请一个指针变量p,&a给p进行了初始化 再将p指向这个变量a的空间<br />    //注意类型一定要对应上 a是int型的 申请的指针p也要是int型的 才能指向a

//指针的赋值

//现在指向的a,赋值的意思就指向另外一块地址<br />    int b = 666;<br />    p = &b;  //赋值的时候p是变量,不用加*,*p声明的时候表示的是p是一个指针变量<br />    //重新指向的时候直接操作变量p就可以了

//通过指针操作所指向的空间

//p本身    就是地址,*p就是所指向的空间<br />    //在声明的时候是标记作用,而这个*是内存操作符,可以同通过这个符号进行读写取地址,解引用运算符<br />    //*解引用运算符;使用方法*+地址,一定要是合法地址,我们申请的,如定义的变量,数组等<br /> <br />    //一个指针指向一个变量,那么 * 这个指针,就是变量本身<br />    //指针p指向一个变量a对应的空间,*p就是a本身,a怎么操作,*p就怎么操作<br />    * p = 666;  //利用指针操作所指向空间<br />    //通过地址间接操作所指向的空间叫间接操作      直接操作,例如变量a赋值12<br />    printf("%d\n%d\n", b, *p);

//类型决定内存操作

//本质,所指向的空间是什么类型,那么*p就一次操作多大的内存空间<br />    //类型是int,就一次操作四个字节的空间,类型是什么就一次操作多少字节的空间<br />    //short a = 12;一个小范围的指针可以指向大范围的空间,并且操作不异常,虽然过不太对<br />    //int *p = &a;一个大范围的指针不可以指向小范围的空间,操作异常,结果更不对。<br /> <br />    system("color c");<br />    return 0;<br />}

测试指针 各个值和地址

include
#include
int main(void)
{
int a = 12;//先定义一个变量
int p = &a; //并赋初始值 指针指向这个变量的地址
//输出各个变量的值和地址
printf(“%d\n%d\n%d\n%d\n%d\n%d\n\n”, &p, a,
p, p, &a, &p);
printf(“%p\n%p\n%p\n%p\n%p\n%p\n\n”, &p, a,
p, p, &a, &p);

//值: 打印各个值 一个指针指向一个变量,那么这么指针就是这个变量本身
p = 12;//通过指针操作所指向地址的空间,可以用p去操作a的空间可赋新值
printf(“%d %d\n\n\n”, p, a); //p == a == 12 (即值一样地址也一样)
//p就是a的值 p等价a

//取地址 打印出的各个地址<br />    printf("%p\n%p\n%p\n%p\n ", &p, p, &a, &*p);<br />    //假设a的地址是0x10 指针p的地址是0x20(即指针p存的的是a的地址)<br />    //&p 是指针变量的地址 (p自己的地址0x20)  <br />    //p 是本身空间里的地址(也就是存的a的地址0x10)    <br />    //&a是a的地址 (a的地址0x10)    <br />    //&*p 是*p的地址也就是指向空间的地址(a的地址0x10)

//各个值: &p(p自己的地址),  a == *p,  p == &a == &*p<br />    //*p就是a本身也就是12, 剩下的都是地址<br />    //各个地址: &p(p自己的地址),  a == *p,  p == &a == &*p<br />    //*p的地址就是a的地址 值一样地址也一样 (值都是12即打印的也是12的地址)<br />    //p的地址就是自身空间的地址也就是存的a的地址<br />    //&*p 取的*p的地址 *p的地址就是&a (因*p等价a)(即&*p == &a)

//总结<br />    //&p     (是单独的值和单独的地址0x20)<br />    //*p == a == 12   (即值一样地址也一样)<br />    //p == &a == &*p  (地址和值一样 值12 地址0x10)<br />    system("color c");<br />    return 0;<br />}

二级指针

include
#include
int main(void)
{
//首先任何值都有地址 ,一级指针的值虽然是地址,但这个地址做为一个值亦需要空间来存放,
//是空间就具有地址 ,这就是存放地址这一值的空间所具有的地址,二级指针就是为了获取这个地址。
//一级指针所关联的是其值(一个地址)名下空间里的数据,这个数据可以是任意类型并做任意用途,
//但二级指针所关联的数据只有一个类型一个用途,就是地址,指针就是两个用途提供目标的读取或改写,
//那么二级指针就是为了提供对于内存地址的读取或改写。
//指针的表现形式是地址,核心是指向关系指针,运算符“”的作用是按照指向关系访问所指向的对象.
//如果存在A指向B的指向关系,则A是B的地址,“
A”表示通过这个指向关系间接访问B.
//如果B的值也是一个指针,它指向C,则B是C的地址,“B”表示间接访问C,如果C是整型、
//实型或者结构体等类型的变量或者是存放这些类型的数据的数组元素,则B(即C的地址)是普通的指针,
//称为一级指针,用于存放一级指针的变量称为一级指针变量,指向一级指针变量的”A”则是“二级指针”。
int a = 12; //a 0x10
int
g = &a; //p 0x20
//证明不同
int g1 = &g ; //2级指针,一个就是一级指针

//要定义指针变量装g的地址,
g1前面的加g指向变量的类型
//g的类型是int类型的,那么就是前面加 int g1 = &g

//
g1表示指针,int表示指向指针的类型,组合到一起int g1 = &g;
int**
g2 = &g1; //1级指针变量的地址,用二级指针来装,同理二级指针的地址用三级来装
//把变量名去了int 定义一个int类型的指针来装二级指针 例如int* j

二级指针的使用

int c = 12;     //a 0x10<br />    int* p = &a;  //p 0x20  //一个指针指向一个变量,那么*这个指针就是这个变量本身<br />    int** p1 = &p;<br />    //int** *p2 = &p1;<br />    printf("%p %p %p\n%p %p\n\n\n", &a, p, &p, *p, &*p);<br />    printf("%p %p\n\n\n", p1, &p1);<br />    printf("%p %p\n%p %p\n\n\n", *p1, &*p1, **p1, &**p1);<br />    printf("%d %d %d\n", a, *p, **p1);<br />    *p == a;<br />    *p1 == p == &a;<br />    **p1 == *p == a;<br />    //p == &a;        *p == a;<br />    //p1 == &p;<br />    //**p1 ==  *p == a;<br />    ////&p1  <br />    //*p1 == &*p == p == &a;  //一个指针指向一个变量,*这个指针,就是那个变量本身<br />    //&*p1 == p1 == &p<br />    //&**p1 == *p1 == p == &a;  //一个*就是解一层,两个就是解两层<br />    //变量的类型,就是空间的类型 a的类型是int型的那么它对应的空间也是int型的<br />    //p是int*型的那么它对应空间的类型也是int*型的<br />    //变量的类型,就是空间的类型  <br />    //a的类型是int型的那么它对应的空间也是int型的<br />    //p是int*型的那么它对应空间的类型也是int*型的<br />    //p1是int**型的那么它对应的空间的类型也是int**型的<br />    system("pause");<br />    return 0;<br />}

指针数组

include
#include
int main(void)
{
//数组元素可以用任何数据类型,假设我有int a b c d e;五个变量,我想把这五个变量的地址用数组装
//&a &b &c &d &e;那么这个数组该如何定义呢。注意这五个变量类型必须相同,这样他们的地址类型才相同
//都是int
int a = 123,
b = 456,
c = 789,
d = 147,
e = 258;
int
g[5] = {&a, &b, &c, &d, &e}; //g前边是每个元素的类型都是int
printf(“%d\n “, c);
g[2] = &c;
//直接用变量名c来赋值也可以
g[2] = 666;//对地址操作要使用解引用运算符
printf(“%d\n”,c);
// 在C语言和C++等语言中,数组元素全为指针变量的数组称为指针数组,
// 指针数组中的元素都必须具有相同的存储类型、指向相同数据类型的指针变量。
// 指针数组比较适合用来指向若干个字符串,使字符串处理更加方便、灵活。
// 一维指针数组的定义形式为:“类型名
数组标识符[数组长度]”。 [1]
system(“pause”);
return 0;
}

指针数组拉链结构

include
#include
int main(void)
{
int b[3] = {2,4,7},
c[2] = {3,6},
d[3] = {4,6,8},
e[4] = {23,43,54,78},
f[3] = {62,85,25};
int* a[5] = {b[0],c,d,e,f}; //数组名就是元素的首地址
a[2] = d;
printf(“%d\n”, a[2][2]); //两层下标运算
//访问格式跟二维数组一样,意义也一样,但结构是不一样的,本质也不一样
//每个小数组大小可以不同,但是元素类型必须相同
//数组指针是指向数组首元素的地址的指针,其本质为指针
//(这个指针存放的是数组首地址的地址,相当于2级指针,这个指针不可移动);
//指针数组是数组元素为指针的数组,其本质为数组。 [3]
system(“pause”);
return 0;
}

利用指针遍历一维数组

include
#include
int main (void)
{
int a[5] = {4, 6, 3, 6, 7};
int p = &a[0]; //指向第一个首元素 //指针类型必须与元素类型一致,这样才能正确读写数据
int i = 0;

(p + 2) = 2323; //利用解引用去赋值
for(i = 0; i < 5; i++)
{ //数组的空间是连续的,地址加减是加的一个类型的大小
printf(“%d\n”, (p + i)); //得到元素的值,要加括号,因为的优先级比括号高
}

//p + 1 ;
//&a[0] + 1;
printf(“%p %p %p %p %p\n”, p+0, p+1, p+2, p+3, p+4);
//printf(“%p “, ++p);
printf(“%p %p %p %p %p\n\n\n”, &a[0], &a[1], &a[2], &a[3], &a[4]);
printf(“%p “, p);
printf(“%p “, ++p);
printf(“%p “, ++p);
printf(“%p “, ++p);
printf(“%p\n”, ++p); //++递增1
printf(“%p “, p); //这个时候的p已经是自加成p4了

system(“pause”);
return 0;
}

指针与下标运算

include
#include
int main(void)
{
int a[5] = {4,3,5,54,74};
int p = &a[0];
int i = 0;
//int b = 43;
//int
p1 = &b; //越界访问了应为b旁边的地址变量没有声明
//*p1[2] = 3424;

//a[3] = 666; //本质 地址+[偏移量]
//p[0] =123;
for (i = 0; i < 5; i++)
{
printf(“%d %d\n”, p[i], a[i]); //元素下标可以运算,指针也可以下标运算
}
//准确的说,下标运算,不是数组专属,只是一个运算符,
//数据可以用这个运算符,那是因为它符合了下标运算符的台条件
//地址+【偏移量】,我们指针也是完全可以的
system(“pause”);
return 0;
}

深入指针与下标运算

include
#include
int main(void)
{
int a[5] = {5,7,4,34,65};
int p = &a[0];
(p+2); //是混合运算,有三种运算符,两种方式都可以赋值
p[2]; //只是一个下标运算,只有一个运算符
printf(“%d %d\n”, (p+2), p[2], 2[p]);
printf(“%d %d\n\n\n”,
(a+2), a[2], 2[a]);
//两种下标运算方法,可以赋值,可以读写取地址
//可以a来参与下标运算,但是不能赋值也不能自变++,而p可以被赋值指向新的地址,下标和自加
//p和2谁在前面都一样,组合
(p+2) = p[2];
(p+2) == *(2+p) == 2[p];

system(“pause”);
return 0;
}

利用指针遍历二维数组

include
#include
int main(void)
{

int a[2][3] = {{2,4,5},{6,7,8}};
/int p = &a[0][0];
p == a;
p == a[0][0];
a[0] == a[0][0];
p == a[0];
printf(“%d %d %d %d %d %d\n”, p[0], p[1], p[2], p[3+2-2], p[4], p[5]);
printf(“%d %d %d %d %d %d\n”,
p, (p+1-1), (p+2), (p+3), (p+4), (p+5));/
{
//int (p)[3] = &a[0];
//
p == a[0];
//a[0][0] == (p)[0];
//
(p+1) == a[1];
//printf(“%d %d %d\n”, (p)[0], ((p+1))[2], p[1][2]);
int (p)[2][3] = &a;
p == a;
printf(“%d %d %d\n”, (p)[0][0], (p)[0][1], (*p)[0][2]);
}
system(“pause”);
return 0;
}

数组指针

include
#include
int main(void)
{
int b[3] = {2,4,7},
c[2] = {3,6},
d[3] = {4,6,8},
e[4] = {23,43,54,78},
f[3] = {62,84,25};
int * a[5] = {&b[0],c,d,e,f};
printf(“%d\n”,a[2][2]);
system(“pause”);
return 0;
}

二维数组指针的定义

include
#include
int main(void)
{
int a[2][3] = {{2,4,6} ,{5,6,7}};
//int p = &a;
int (
p)[2][3] = &a;
int j,k;
for (j = 0; j < 2; j++)
{
for (k = 0; k < 3; k++)
{
printf(“%d “,(p)[j][k]);//p == a;
}
}

system(“pause”);
return 0;
}

指针数组 和 数组指针 测试

include
#include
int main(void)
{
int b=24, c=45, d=65, e=35, f=78;
int a[5] ={&b, &c, &d, &e, &f};
//指针数组是数组元素为指针的数组,其本质为数组。 [3]

//在C语言和C++等语言中,数组元素全为指针变量的数组称为指针数组,
//指针数组中的元素都必须具有相同的存储类型、指向相同数据类型的指针变量。
//指针数组比较适合用来指向若干个字符串,使字符串处理更加方便、灵活。
//一维指针数组的定义形式为:“类型名
数组标识符[数组长度]”。[1]
/指针数组,就是说首先是一个数组,而数组的元素是指针,也就是说,
如果数组元素都是相同类型的指针,则称这个数组为指针数组。
所谓相同类型的指针是说指针所指向的对象类型是相同的。一维指针数组的定义形式为:
指针数组中的每一个元素均为指针,即有诸形如“ptr_array[i]”的指针。
由于数组元素均为指针,因此ptr_array[i]是指第i+1个元素的指针。 [2]
/
c = 123;
a[2] = 666;
printf(“%d %d\n”, c,
a[2]);
{
//数组指针是指向数组首元素的地址的指针,其本质为指针
//(这个指针存放的是数组首地址的地址,相当于2级指针,这个指针不可移动);
//要声明指向数组类型的指针,必须使用括号,如下所示:
//int ( arrPtr)[10] = NULL; // 一个指针,它指向一个有10个int元素的数组
//如果没有括号,则声明 int
arrPtr[l0];表示 arrPtr 是一个具有 10 个 int 类型指针的数组。
int q[5] = {5,3,4,7,8};
int f = &q[0];
//int
e = &q
int (d)[5] = q;
d == q;
(d)[2] = 123;
(
d)[3] = 666;
printf(“%d %d”, (d)[2], (d)[3]);
}
system(“pause”);
return 0;
}

指针变量的大小

include
#include
int main(void)
{
int p; //32位的系统支持 = || > 32位的软件,64位系统支持32 64位的软件
short
p4; //32位的程序/软件是4字节指针,64位的程序是8字节指针。 /程序的位数由编译器环境决定,可以设置 而不是由系统给决定
float p5; //所以,32位的系统最大支持4字节指针,64位系统最大支持8字节指针
double
p1;
int (p2) [2][3];
int (
p3) [4];
printf(“%d %d\n”, sizeof(p), sizeof(int)); //可以用变量名和类型来输出变量的字节大小
printf(“%d %d\n”, sizeof(p1), sizeof(double
));
printf(“%d %d\n”, sizeof(p2), sizeof(int ()[2][3]));
printf(“%d %d\n”, sizeof(p3), sizeof(int (
)[4]));
printf(“%d %d\n”, sizeof(p4), sizeof(short));
printf(“%d %d\n”, sizeof(p5), sizeof(float
));
system(“pause”);
return 0;
}