指针
数组指针与指针数组
数组指针
定义
概念:数组指针是指向数组的指针,本质上还是指针
特点:
①先有数组,后有指针
②它指向的是一个完整的数组
一维数组指针
语法:
数据类型 (*指针变量名)[容量];
案例:
/*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;}
##