指针
数组指针与指针数组
数组指针
定义
概念:数组指针是指向数组的指针,本质上还是指针
特点:
①先有数组,后有指针
②它指向的是一个完整的数组
一维数组指针
语法:
数据类型 (*指针变量名)[容量];
案例:
/*int arr[] = {11,22,33,44,55}; int *p = arr; p++; */ /************************************************************************* > File Name: demo01.c > Author: 赵生鑫 > Description: > Created Time: 2025年03月20日 星期四 09时48分24秒 ************************************************************************/ #include <stdio.h> /* * *数组指针:指向数组的指针(这里指向整个数组,不是数组的某个元素) * * */ int main(int argc,char *argv[]) { //一维数组指针 //先有数组,再有指针 //指针不能独立存在,必须依赖与现有的常量或者变量空间 int arr[] = {100,200,300}; //获取数组大小 int len = sizeof(arr) / sizeof(arr[0]); //指针变量指向数组元素:此时指针指向的时数组中的第一个元素,此时指针存储的值是首元素的地址值 //数组指针指向整个数组:此时指针指向的是整个数组,此时指针存储的值是首元素的地址值 //定义一个数组指针 int (*p)[3] = &arr;//arr默认指向首元素,&arr指向整个数组 //p++ 此时不能p++,否则会越界 printf("%p,%p,%p\n",p,&arr,arr);//输出3个地址相等 //如何访问数组指针 printf("%d\n",(*p)[2]); //遍历数组指针 for ( int i = 0;i < len ;i++) { printf("%-6d",(*p)[i]);//数组指针本质是指针,所以我们需要添加()提升指针优先级(默认数组优先) } printf("\n"); return 0; }
我们之前所学的是指向数组元素的指针,本质上是指针变量;现在我们学的是指向数组的指针,叫做数组指针
二维数组指针
语法:
数据类型 (*指针变量名)[行容量][列容量];
案例:
写法1
/************************************************************************* > File Name: demo02.c > Author: 赵生鑫 > Description: > Created Time: 2025年03月20日 星期四 10时17分55秒 ************************************************************************/ #include <stdio.h> int main(int argc,char *argv[]) { int arr[][3] = {11,22,33,44,55,66,77,88,99}; //定义一个数组指针指向二维数组arr //int (*p)[][3] = &arr; 数组指针指向二维数组,不推荐 int (*p)[3] = arr;//数组指针指向二维数组首行,推荐 //遍历(数组方式) for(int i = 0; i < 3;i++) { for(int j = 0;j < 3;j++) { printf("%-6d",p[i][j]);//arr的地址 等于 p存储的值,也就意味着p等价与arr } printf("\n"); } //p++;//此时是可以使用,因为p指向的是arr中的行,默认为首行 return 0; }
写法2
/************************************************************************* > File Name: demo02.c > Author: 赵生鑫 > Description: > Created Time: 2025年03月20日 星期四 10时17分55秒 ************************************************************************/ #include <stdio.h> int main(int argc,char *argv[]) { int arr[][3] = {11,22,33,44,55,66,77,88,99}; //定义一个数组指针指向二维数组arr //int (*p)[][3] = &arr; 数组指针指向二维数组,不推荐 int (*p)[3] = arr;//数组指针指向二维数组首行,推荐 int rows = sizeof(arr) / sizeof(arr[0]); int cols = sizeof(arr) / sizeof(arr[0]); for(int i = 0;i < rows;i++) { for(int j = 0;j < cols;j++) { //三种写法 //1.指针数组语法 printf("%-6d",p[i][j]); //2.指针解引用 printf("%-6d",*(*(p + i) + j)); //3.混合法 printf("%-6d",(*(p + i))[j]);//解引用符*和数组访问符[]在一起时,默认的[]优先级高 } printf("\n"); } //p++;//此时是可以使用,因为p指向的是arr中的行,默认为首行 return 0; }
指针和数组中的符号优先级
() > [] > *
通过指针引用二维数组
注意:二维数组中,数组整体的地址值 = 数组中0行元素的地址值 = 数组中0行0列元素的地址值
案例
案例1
需求:用指向元素的指针变量输出二维数组元素的值
代码:
/************************************************************************* > File Name: demo03.c > Author: 赵生鑫 > Description: > Created Time: 2025年03月20日 星期四 11时46分00秒 ************************************************************************/ #include <stdio.h> int main(int argc,char *argv[]) { //定义一个普通二维数组 int arr[3][4] = {10,20,30,40,100,200,300,400,1000,2000,3000,4000}; //定义一个指针变量,用来接收二维数组的元素 int *p = arr[0];//0列的位置 //获取元素个数 int len = (sizeof(arr) / sizeof(arr[0])) * (sizeof(arr[0]) / sizeof(arr[0][0])); //遍历数组 for(;p < arr[0]+len;p++) { //每4个换行 if((p - arr[0]) % 4 == 0) printf("\n"); printf("%-6d",*p); } printf("\n"); return 0; }
指针数组
定义:指针数组是一个数组,数组中的每一个元素都是一个指针
特点:
先有指针,后有数组
指针数组的本质是一个数组,只是数组中的元素类型是指针
语法:
数据类型 *数组名[容量];
#include <stdio.h> int main() { //定义三个变量 int a = 10,b = 20,c = 30; //定义指针数组,指针数组是用来存储指针 int *arr[3] = {&a,&b,&c}; //获取数组大小 int len = sizeof(arr) / sizeof(arr[0]); //遍历数组 for(int i = 0;i < len; i++) { pritnf("%-3d",*arr[i]6); } return 0; }
建议:我们一般使用指针数组处理字符串。
数组指针与指针数组的区别

字符数组和字符指针
字符串实现
再C语言中,表示一个字符串有以下两种方式:
①数组形式:用字符数组存放一个字符串
②指针形式:用字符指针指向一个字符串
案例
#include <stdio.h> /* 方式1:使用字符数组实现字符串 */ void str_test1() { //定义一个伪字符串 char str[] = " I LOVE YOU"; printf("%s\n",str); } /* 方式2:使用字符指针实现字符串 */ void str_test2() { //定义一个伪字符串 char *str = "I LOVE YOU"; printf("%s\n",str); } int main() { str_test1(); str_test2(); return 0; }
注意:字符数组和字符指针变量都能实现字符串的存储与运算。(字符指针→字符类型的指针变量)
字符数组和字符指针的联系
概念
字符数组由元素组成,每个元素中存放一个字符,而字符指针变量中存放的是地址(可以作为函数参数)
只能对字符数组中的各个元素赋值,而不能用赋值语句对整个字符数组赋值
char arr[3] = {}; arr[2] = 'A';//正确,对字符数组中的元素赋值 arr = {'E','D','F'};//错误,对整个数组赋值(可以理解为数组就是一个常量,一旦创建,就无法改变)
字符数组名虽然代表地址,但数组名的值不能改变,因为数组名是常量(参照上面案例)
对应字符串中的字符的存取,可以用下标法,也可以用指针法。
案例
#include <stdio.h> int mian() { //使用两种方式测试字符串 char str1[] = "你好,佩奇!"; char *str2 = "你好,乔治!"; //赋值测试 str1 = "你好啊,佩奇!!";//数组一旦创建就无法改变其值,可以理解为数组名是常量 str2 = "你好啊,乔治!!"; //打印测试 printf("%s,%s\n",str1,str2); /*//以下代码会报错 //给字符串赋值 char *str3 = NULL;//未初始化的指针,指针一定要有指向,需要指向一个具体的内存空间 printf("请输入一个符串:\n"); scanf("%s",str3); printf("%s\n ",str3); */ char a[] = "I LOVE YOU"; char *b = "I LOVE YOU"; //使用下标法和指针法分别访问字符串 printf("%c,%c\n,%c\n",a[2],*(a+2),b[2],*(b+2)) return 0; }
字符串作为形式参数
定义
实参与形参都可以是字符数组
void fun(char str[],int len){...} void mian() { char str[] = "hello"; fun(str,sizeof(str) / sizeof(str[0])) }
实参用字符数组,形参用字符指针
void fun(char *str,int len){...} void mian() { char *str = "hello"; fun(str,sizeof(str) / sizeof(str[0])) }
形参和实现都是指针变量(在函数内部中不对字符串中的字符做修改)
void fun(char *str,int len) { //在函数内部中不对字符串中的字符做修改,否则报段错误 //*(str + 2) = 'A'; //str[2] = 'A'; printf("%s\n",str); } void mian() { char *str = "hello"; fun(str,sizeof(str) / sizeof(str[0])) }
实参是指针类型,形参是字符数组(在函数内部中不对字符串中的字符做修改)
void fun(char str[],int len) { //在函数内部中不对字符串中的字符做修改,否则报段错误 //*(str + 2) = 'A'; //str[2] = 'A'; printf("%s\n",str); } void mian() { char *str = "hello"; fun(str,sizeof(str) / sizeof(str[0])) }
注意
1.字符数组在创建的时候,会在内存中开辟内存空间,内存空间可以存放字符数据;字符指针在创建的时 候,需要依赖于字符数组,字符指针在内存开辟的内存空间中,存放的是数组元素的地址。字符指针的 创建依赖于字符数组,字符数组可以独立存在,而字符指针不能独立存在。 2.字符数组可以初始化,但是不能赋值;字符指针可以初始化,也可以赋值。
案例
案例1
需求:字符指针作为函数参考:用函数调用实现字符串的复制及长度计算
代码:
/************************************************************************* > File Name: demo04.c > Author: 赵生鑫 > Description: > Created Time: 2025年03月20日 星期四 16时55分04秒 ************************************************************************/ #include <stdio.h> /* * *定义一个函数,实现字符串的拷贝,返回字符串的长度 *@param source拷贝的源字符串 *@param target需要拷贝保存字符串的目标字符串 *@return 字符串长度 * * */ int str_copy(const char *source,char *target) { //定义一个循环变量 register int i = 0; //循环的遍历 while(source[i] != '\0') { //实现拷贝 *(target + i) = *(source + i);//指针法 //下标法 target[i] = source[i]; i++; } //拷贝结束后,一定给target加上\0 *(target + i) = '\0'; return i; } int main(int argc,char *argv[]) { //定义两个数组,从键盘录入字符串 char source[20],target[20]; printf("请输入一个字符串:\n"); scanf("%s",source); //拷贝并复制长度 int len = str_copy(source,target); printf("字符串:%s的长度是%d\n",target,len); return 0; }
案例2
需求:字符指针作为函数的参数-给定一个字符串,截取start到end之间的字符串,含头不含尾
代码:
/************************************************************************* > File Name: demo05.c > Author: 赵生鑫 > Description: > Created Time: 2025年03月20日 星期四 17时08分51秒 ************************************************************************/ #include <stdio.h> /* *定义一个函数,实现字符串的截取(含头不含尾) *@param source源字符串 *@param start开始截取的位置(下标) *@param end结束截取的位置(下标) *@param target截取出来的字符串 *@return target的串长 * * */ int str_substr(const char *source,int start,int end,char *target) { //定义循环变量(i时source取的下标,k时target存的下标) register int i = 0,k = 0; //遍历源字符串 while(source[i] != '\0') { //根据start和end截取 if(i >= start && i < end) { //下标法target[k] = source[i]; *(target + k) = *(source + i); k++; } i++; } //target截取结束,需要添加\0 *(target + k) = '\0'; return k; } int main(int argc,char *argv[]) { char *str = "abcdefg"; char target[26]; int len = str_substr(str,2,5,target); printf("%s,%s,%d\n",str,target,len); return 0; }
##