开封做网站公司,做公众号试卷的网站,如何从零开始学室内设计,wordpress屏蔽登陆按钮文章目录 前言指向整型变量的指针指向一维数组的指针以指针为形参且以指针为返回值类型以局部变量地址作为返回值存在的安全隐患 指向字符串的指针通过指针交换两变量的值多级指针指针数组数组指针指向函数的指针 前言
C语言中的指针实质是指向某一对象的内存地址#xff0c;… 文章目录 前言指向整型变量的指针指向一维数组的指针以指针为形参且以指针为返回值类型以局部变量地址作为返回值存在的安全隐患 指向字符串的指针通过指针交换两变量的值多级指针指针数组数组指针指向函数的指针 前言
C语言中的指针实质是指向某一对象的内存地址对象可以是变量、常量、数组、函数等。不同类型的指针大小是不变的例如在64位操作系统中指针大小占8个字节。可以对地址进行前移、后移运算可以通过运算符*获取内存地址保存的数据。
操作系统大小(字节)备注62位8int*、float*、char*等指针大小均为8字节32位4int*、float*、char*等指针大小均为4字节 指向整型变量的指针
建立一个整型变量num假设其地址为1000并在其内存空间中保存数据10建立一个整型变量temporary假设其地址为1020并在其内存空间中保存数据20建立一个整型指针变量p指向num的地址也就是地址1000此时p和num指向同一个内存地址将指针p指向的地址中保存的数据更改为temporary的数据即修改为20因为p和num指向同一个内存地址,故*p和num的值均被更改为20 以此可以推导出其他基本数据类型指针的简单运用
/// Description 指向整形变量的指针
void varPrime(){int num 10,temporary 20;//一个整形指针变量指向了一个整形变量的地址int *p num;//修改p指向的地址中的数据内容*p temporary;printf(%d,num);
}指向一维数组的指针
array是一个一维整型数据代表首元素首地址也就是array[0]整型指针变量p指向array的首元素首地址假设首元素首地址为1000p;即代表地址后移(1000(1*4))1004因为int型在64位操作系统中占4个字节故每次进行地址移动以4位倍数执行完p;后p当前指向数组内第二个元素array[1]的地址p–;即代表地址前移(1004-(1*4))1000因为上一次执行完之后p指向的地址是1004故从此地址开始计算执行完p–;后p当前指向数组内第一个元素array[0]的地址*(pi)因为一维数组采用顺序存储拥有随机访问的特点因为指针指向的数组也可以通过随机访问进行读取内存空间上的数据
/// Description 指向一维数组的指针
void oneArrayPrime(){int array[] {10,20,30};//因为array代表的是数组的首元素地址故前面不需要加地址符号int *p array;//数组下标后移初始化指向第一个元素10后移操作之后指向20p;//数组下标前移继上一个操作之后指针指向元素10前移操作之后指向10p--;//遍历数组输出数组所有内容for(int i0; i3; i){printf(current element: %d\n,*(pi));}
}以指针为形参且以指针为返回值类型
通过在一个数组内寻找最大值的例子概述以指针为形参且以指针为返回值类型
实参中传入一维数组的首元素首地址形参则使用一个整型指针来进行传递此指针指向一维数组的首元素首地址然后在通过地址符号返回最大值的地址同样因为是地址所以返回值类型需要变为指针来进行传递此处以局部变量地址作为返回值存在一定安全隐患将在下一节讲述
/// Description 数组作为函数实参指针作为函数形参寻找数组内最大值,并以指针作为返回值类型
/// - Parameters:
/// - array: 整形指针变量指向一维数组
/// - size: 数组长度
int* findMax(int *array,int length){int max *array;for(int i1; ilength; i){if(*(arrayi) max) max *(arrayi);}return max;
}void testMax(){int array[] {1,2,3,4};int length sizeof(array) / sizeof(int);int *max findMax(array, length);printf(max%d\n,*max);
}以局部变量地址作为返回值存在的安全隐患
List item上述寻找最大值例子以局部变量地址作为返回值进行返回但上述例子可以正常运行而下列例子则存在安全隐患。因为当函数执行完成之后系统会对此函数进行回收其局部变量也被回收但系统会留有一个时机上述例子抓住时机并将其进行输出。而下列例子在中间穿插了一句代码导致错过时机指针变量p变为野指针指向一个系统随机分配的地址。一般会保留一个语句的执行频度(各编译器存在差异)也就是说当下一个语句执行完后系统会对其进行释放
int* returnPrime(){int n 10;return n;
}/// Description 接受来自另一个函数的局部变量返回值
/// 当函数执行完成后系统不会立即回收此地址
///一般会保留一个语句的执行时间(各编译器存在差异)也就是说当下一个语句执行完后系统会对其进行释放
///所以p指向的地址被系统释放故随后指向一个随机的地址
void testReturnPrime(){int *p returnPrime();printf(split line!\n);printf(n%d\n,*p);
}指向字符串的指针
字符串不等同于字符数组
类型举例长度区别字符数组char str1[] {‘a’,‘b’,‘c’};3系统不会默认在结尾追加结尾符\0字符串char str2[] “abc”;4系统会默认在结尾追加结尾符\0
字符指针p指向字符串str首元素首地址因为str代表的就是首元素首地址本身就是一个地址所以在赋值给字符指针p时无须加地址符号此处区别于上述指针整型变量的指针
/// Description 指向字符串的指针
void stringPrime(){//字符串系统默认在其最后添加结尾符\0char str[] Hello World!;char tempStr[] C Prime!;//字符指针变量p指向字符串首元素首地址char *p str;int size strlen(p);printf(The array length:%d\n,size);//输出方式一直接使用字符串方式输出因为数组str占据着一连串连续的地址空间printf(%s\n,p);//输出方式二通过类似数组str[i]的方式逐个访问地址然后输出for(int i0; isize; i){printf(%c,*(pi));}putchar(\n);//输出方式三通过指针后移操作改变指向的地址依次读取输出for(;*p!\0;p){printf(%c,*p);}putchar(\n);//更改字符指针指向的地址p tempStr;printf(%s\n,p);putchar(\n);
}通过指针交换两变量的值
*a *b这一句为关键代表着将b内存地址上的内容赋值到a内存地址上则将原本a的内容进行覆盖 如果将上述第三行代码改为ab;取消两端的指针*运算 则形参a指向b的地址但由于未使用指针进行运算形参a的内容只保留在局部范围之内不改变实参数a的内容 故输出a1,b1 /// Description 通过将整形指针变量作文形参交换两个变量的值
/// - Parameters:
/// - a: 第一个指针变量
/// - b: 另一个指针变量
void swap(int *a,int *b){int temp;temp *a;*a *b;*b temp;//如果将上述第三行代码改为ab;取消两端的指针取值操作//则形参a指向b的地址但由于未使用指针进行运算形参a的内容只保留在局部范围之内不改变实参数a的内容//故输出a1,b1
}
void testSwap(){int a1,b2;printf(before swap:a%d,b%d\n,a,b);swap(a, b);printf(after swap:a%d,b%d\n,a,b);
}多级指针
一级整型指针变量指向a的地址二级指针指向一级指针的地址依次类推可以换一种思维把二级指针看作一级指针一级指针看作一个变量各“向下降一级就回到一级整型指针变量指向变量a的地址***p3等同于*(*(*p3))从括弧内往外剖析 最里面的(p3)取出的是p2的地址 然后第二层就为(p2)取出来的是p1的地址 第一层就为(p1)的值 则p3取的是变量a的值 void multPrime(){int a 10;//一级整型指针变量指向a的地址int *p1 a;//二级指针指向一级指针的地址//可以换一种思维把二级指针看作一级指针一级指针看作一个变量各“向下降一级就回到第一条语句思想int **p2 p1;//***p3可以看作是*(*(*p3))//从内往外剖析//最里面的(*p3)取出的是p2的地址//然后第二层就为(*p2)取出来的是p1的地址//第一层就为(*p1)的值int ***p3 p2;printf(p1%d\n,*p1);printf(p2%d\n,**p2);printf(p3%d\n,*(*(*p3)));
}指针数组
定义指针数组包含n个元素其中每一个元素都是指针 例如: int * p[n]; 其中[]的运算优先级大于*,p为数组其类型为int*则数组内每个元素类型皆为int* 下列指针数组array中保存p1,p2,p3三个整型指针变量同样因为是数组具有随机访问的特性**(arrayi)等同于*(*(arrayi))其中*(arrayi)获取是第i个元素因为元素是指针是指向的一个内存地址故*(arrayi)取出的是pi的地址再在外面加一个取值*符号就是对*pi等于*(*(arrayi))进行取值运算获取其内存空间的数据
/// Description 指针数组包含n个元素其中每一个元素都是指针
/// 例如: int * p[n];
/// 其中[]的运算优先级大于*,p为数组其类型为int*则数组内每个元素类型皆为int*
void primeArray(){int a 10,b20,c30;int *p1a,*p2b,*p3c;//定义一个整型指针数组包含3个元素其中每一个元素都是整形指针int *array[] {p1,p2,p3};//*指针在32位操作系统占4个字节在64位操作系统占8个字节,//与其类型无关int*,char*,float*...在64位操作系统都占占8个字节int length sizeof(array) / sizeof(int*);for(int i0; ilength; i){printf(%d ,**(arrayi));}}数组指针
定义数组指针指向数组的指针 例如int (*p)[n]; ()的优先级大于[]p为指针指向n个一维数组 此处的n必须与二维数组的列数保持一致(以二维为例) int (*q)[3] b;数组指针p指向一个2行3列的二维数组的首元素首地址*(*(qi)j)其中*(qi)先获取二维数组的地址*(qi)j获取b[i][j]的地址最后在外面使用*取值运算即获取b[i][j]的值
/// Description 数组指针指向数组的指针
/// 例如int (*p)[n];
/// ()的优先级大于[]p为指针指向n个一维数组
void Arrayprime(){int a[5] {1,2,3,4,5};int (*p)[5] a;for(int i0; i5; i){//因为a是一维的只有一行所以下列语句等同于p[0][i]printf(%d ,*(*pi));}putchar(\n);int b[2][3] {{1,2,3},{4,5,6}};int (*q)[3] b;for (int i0; i2; i) {for (int j0; j3; j) {printf(%d ,*(*(qi)j));}putchar(\n);}
}指向函数的指针
此处以寻找最小值为例 int (*p)(int,int) findMin; 从左到右结合第一个(*p)大于第二个()故p为一个指针指向一个函数 函数指针p的函数参数定义必须和所指向函数的参数类型、个数、顺序保持一致函数指针中的函数参数定义可以省略具体的参数名
int findMin(int a,int b){return ab? a : b;
}/// Description 函数指针顾名思义指向函数的指针
void functionPrime(){int a1,b2;//其中函数指针指向函数定义对应的参数名称可省略//从左到右结合第一个(*p)大于第二个()故p为一个指针指向一个函数int (*p)(int,int) findMin;int min (*p)(a,b);printf(min%d\n,min);
}