指针
数组指针与指针数组
数组指针
指针和数组中符号优先级
() > [] > *
通过指针引用二维数组
表示形式 | 含义 | 地址/值 |
---|---|---|
a |
二维数组名,指向一维数组a[0] (0行首地址) | 2000 |
a[0],*(a+0 ),*a |
0行0列元素地址 | 2000 |
a + 1,&a[1] |
1行首地址 | 2008 |
a[1], *(a + 1) |
1行0列元素a[1] [0]的地址 | 2008 |
a[1],*(a+1)+2,&a[1][2] |
1行2列元素a[1] [2]的地址 | 2012 |
*(a[1]+2),*(*(a+1) +2),a[1][2] |
1行2列元素a[1] [2]的值 | 元素值为13 |
注意:二维数组中,数组整体的地址值 == 数组中0行元素的地址值 == 数组中0行0列元素的地址 值
案例
案例1
需求:用指向元素的指针变量输出二维数组的值
代码:
/************************************************************************* > File Name: demo02.c > Author: 小刘 > Description: > Created Time: 2025年05月21日 星期三 11时44分03秒 ************************************************************************/ #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]; // 获取元素的个数 int len = (sizeof(arr)/sizeof(arr[0]) * sizeof(arr[0])/sizeof(arr[0][0])); //遍历数组 //通过指针变量访问二维数组,只需要一层for循环 for(;p <arr[0] +len ; p++) { //每四行换行 if((p - arr[0]) % 4 == 0 && p != arr[0])printf("\n"); printf("%-6d",*p); } printf("\n"); return 0; }
案例2:
需求:数组指针- 输出二维数组任一行任意列元素的值
代码:
/************************************************************************* > File Name: demo03.c > Author: 小刘 > Description: > Created Time: 2025年05月21日 星期三 12时00分44秒 ************************************************************************/ #include <stdio.h> int main(int argc,char *argv[]) { // 定义一个二维数组 int arr[3][4] = {1,3,5,7,11,33,55,77,111,333,555,777}; //创建一个数组指针指向二维数组 int (*p)[4] = arr; // 二维数组中的第一个元素就是首行 // 创建两个变量,接收控制台输入的行和列 int row, col; printf("请输入行号和列号:\n"); scanf("%d,%d",&row,&col); printf("arr[%d][%d]=%d,%d,%d,%d\n",row,col,*(*(p+row)+col),(*(p+row))[col],*(p[row]+col),p[row][col]); return 0; }
指针数组
**定义:**指针数组是一个数组,数组中每一个元素都是一个指针。
特点:
- 现有指针后又数组
- 指针数组的本质是一个数组,只是数组元素类型是指针。
语法:
数据类型 *数组名[容量]
案例:
/*************************************************************************
> File Name: demo04.c
> Author: 小刘
> Description:
> Created Time: 2025年05月21日 星期三 14时16分51秒
************************************************************************/
#include <stdio.h>
int main(int argc,char *argv[])
{
//定义三个变量
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++)
{
printf("%-3d",*arr[i]);//arr先跟[]结合取出地址,地址再跟左侧×结合,解引用出地址对应空间的数据
}
printf("\n");
return 0;
}
建议:我们一般使用指针数组处理字符串。
数据指针与指针数组的区别
对比项 | 指针数组 | 数组指针 |
---|---|---|
定义 | 数组元素均为指针的数组 | 指向一个完整数组的指针 |
存储内容 | 存储多个指针,每个元素指向不同内存地址 | 存储单个指针,指向一个完整的数组(首地址) |
内存分配 | 每个指针元素独立分配内存,可能分散 | 指向的数组内连续,指针本身存储数组首地址 |
语法示例 | int *arr[5] ;(元素为5个int *指针) |
int (*ptr)[5] ;(指向含5个int数组的指针) |
访问方式 | 通过下标访问指针元素,再解引用:*arr[i] |
先解引用指针得到数组,再访问元素:(*ptr) [i]或ptr[0][i] |
使用场景 | 管理多个独立指针(如字符串数组、动态结构体数组) | 操作多维数组(如传递二维数组的行指针) |
内存布局示意图 | [ptr1] → 数据1 [ptr2] →数据2… | ptr → [数据1] [数据2] [数据3] [数据4] [数据5 ] |
示例代码 | int a=1, b=2;int *arr[]<b= {&a, &b} ; |
int arr[2][3] ={1,2,3,4,5,6};int (*ptr)[3] =arr |
字符数组和字符指针
字符串的实现
char atr[20] = "李白";
char *str = "李白"
在C语言中,表示一个字符串有以下两种方式:
①数组形式:用字符数组存放一个字符串
②指针形式:用字符指针存放一个字符串
/*************************************************************************
> File Name: demo06.c
> Author: 小刘
> Description:
> Created Time: 2025年05月26日 星期一 21时56分23秒
************************************************************************/
#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(int argc,char *argv[])
{
str_test1();
str_test2();
return 0;
}
注意:字符数组和字符指针变量都能实现字符串的存储与运算。(字符指针---->字符类型的指针变量)
字符数组和字符指针的联系
概念
- 字符数组由元素组成,每一个元素存放一个字符:而字符指针(变量)中存放的是地址(可以作为函数参数)
char str[] = {'i','0'};
只能对字符数组中元素赋值,而不能用赋值语句对整个字符数组赋值。
char arr[3] ={}; arr[2] = 'A'; //正确,对字符数组中的元素赋值 arr = {'E','D','F'};//错误,对整个数组赋值(可以理解为数组名就是一个常量,一旦创建就无法改变)
字符数组虽然代表地址,但数组名的值不能改变,因为数组名是常量。
对于字符串中的存取,可以用下标法,也可以用指针法。
案例
/*************************************************************************
> File Name: demo05.c
> Author: 小刘
> Description:
> Created Time: 2025年05月21日 星期三 14时58分20秒
************************************************************************/
#include <stdio.h>
int main(int argc,char *argv[])
{
// 使用两种方式创建字符串
char str1[] = "你好,中国!";
char *str2 = "你好,陕西!";
// 赋值测试
// str1 = "你好,未来";//错误,数组一旦创建,就无法改变其值
str2 = "创新未来";
printf("%s,%s\n",str1,str2);
//char *str;
printf("请输入一个字符串:\n");
scanf("%s",&str);
printf("输出-%s\n",str);
char a[] = "I LOVE CHIAN";
char *b = "I LOVE CHINA";
printf("%c,%c\n%c,%c\n%s,%s\n",a[2],*(a+2),b[2],*(b+2),a+2,b+2);
return 0;
}
字符串作为形式参数
定义:
实参与形参都可以是字符数组
void fun(char str[], int len){..} void main() { char str[] = "hello"; int len = sizeof(str)/sizeof(str[0]); fun(str,len); }
实参用字符数组,形参用字符指针
void fun(char *str, int len){..} void main() { char str[] = "hello"; int len = sizeof(str)/sizeof(str[0]); fun(str,len); }
形参和实参都是指针(在函数内部不能对字符串中的字符做修改)
#include <stdio.h> void fun(char *str, int len) { // 在函数内部不能对字符串中的字符做修改,否则报错 段错误 // *(str+1) = 'E'; // str[2] = 'L'; printf("%s\n",str); // hELlo } int main(int argc,char *argv[]) { char *str = "hello"; int len = sizeof(str)/sizeof(str[0]); fun(str,len); return 0; }
实参是指针类型形参是字符数组
#include <stdio.h> void fun(char str[], int len) { // 在函数内部不能对字符串中的字符做修改,否则报错 段错误 // *(str+1) = 'E'; // str[2] = 'L'; printf("%s\n",str); // hELlo } int main(int argc,char *argv[]) { char *str = "hello"; int len = sizeof(str)/sizeof(str[0]); fun(str,len); return 0; }
注意:
字符数组在创建的时候,会在内存中开辟内存空间,内存空间可以存放字符数据;字符指针在创建的时候,需要依赖于字符数组,字符指针在内存开辟的内存空间中,存放的是数组元素的地址。字符指针的创建依赖于字符数组,字符数组可以独立存在,而字符指针不能独立存在。
字符数组可以初始化,但是不能赋值;字符指针可以初始化,也可以赋值。
char str1[] = "helllo";//对数组初始化 str1 = "hi"; //对数组赋值,此时错误 str[0] = 'h'; //对数组中的元素赋值,此时正确
案例
案例1
- 需求:字符指针作为函数参数:用函数调用实现字符串的复制以及长度计算
- 代码:
/*************************************************************************
> File Name: demo07.c
> Author: 小刘
> Description:
> Created Time: 2025年05月21日 星期三 16时14分24秒
************************************************************************/
#include <stdio.h>
int str_cpy(const char *source,char *target)
{
register int i = 0;
while(source[i] != '\0')
{
*(target + i) = *(source + i);
i++;
}
*(target + i) = '\0';
return i;
}
int main(int argc,char *argv[])
{
char source[20],target[20];
scanf("%s",source);
int len = str_cpy(source,target);
printf("字符串:%s的长度为:%d\n",source,len);
return 0;
}
运行结果:
案例2
需求:字符指针作为函数的参数- 给定一个字符串
代码::
/************************************************************************* > File Name: demo08.c > Author: 小刘 > Description: > Created Time: 2025年05月21日 星期三 16时27分46秒 ************************************************************************/ #include <stdio.h> /** * 定义一个函数,实现字符串的截取 * @param source 源字符串 * @param start 开始位置 * @param end 结束位置 * @param target 目标字符串 * @return 目标字符串长度 */ int str_substr(char *source,int start,int end,char *target) { register int i = 0,k = 0; // 遍历源字符串 while (source[i] != '\0') { // 根据start和end截取 if(i >= start && i < end) { *(target + k) = *(source + i); k++; } i++; } *(target + k) = '\0'; return k; } int main(int argc,char *argv[]) { char *str = "abcdefg";// cde char target[26]; int len = str_substr(str,2,5,target); printf("%s,%s,%d\n",str,target,len); return 0; }