持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第18天,点击查看活动详情
前言
💨 在C语言初识篇我们大概的对指针有了一些简单认识和概念。在正式对指针进阶的学习之前,先简单回忆下:
- 指针就是一个变量,用来存放地址,地址唯一标识一块内存空间
- 指针的大小是固定的4/8个字节(32位平台/64位平台)
- 指针是有类型的,指针的类型决定了指针加减整数的步长;指针解引用操作的时候的权限
- 指针的运算
一、字符指针
1、什么是字符指针
💨 顾名思义就是指向字符的指针
int main() { char ch = 'q'; char* pc = &ch; return 0; }
💨 当然也可以指向字符串
int main() { ==//这里的字符串占了10个字节的空间,指针大小最大也就8个字节,怎么可能存的下。其实这里存储的是字符串的首元素的地址== char* pc = "hello bit"; ==//不防一验:(对pc进行解引用,并输出。如果输出'h'则证实指针存储的是字符串的首元素地址)== printf("%c\n", *pc); ==//相对于数组,字符串会被全部存储于内存中== char arr[] = "hello bit" ==//当采用指针变量和数组首地址来输出字符串时,两者很相似== printf("%s\n", ps); printf("%s\n", arr); return 0; }
💨 常量字符串
2、 字符指针实例1:(出自《剑指offer》)
#include<stdio.h>
int main()
{
char str1[] = "hello bit.";
char str2[] = "hello bit.";
const char* str3 = "hello bit.";
const char* str4 = "hello bit.";
if(str1 == str2)
printf("str1 and str2 are same\n");
else
printf("str1 and str2 are not same\n");
if(str3 == str4)
printf("str3 and str4 are same\n");
else
printf("str3 and str4 are not same\n");
return 0;
}
输出结果:
分析: 两者都是对地址的比较 ==前者:对于数组来说要开辟两块不同的内存空间== 所以地址当然不相同
==后者:对于一个指向一个字符串的指针来说,这个字符串是常量不能被修改(因为不能修改,所以在内存里也没有同时存在2份及以上的必要)== 因为str3和str4同时指向同一块空间,所以它们的地址是相同的
二、指针数组
1、什么是指针数组
💨 整型数组存放整型,字符数组存放字符。顾名思义指针数组就是一个存放指针的数组
int* arr[3]; arr数组里有3个元素,每个元素是int*类型的
2、怎么用
💨 这里介绍两种写法
#include<stdio.h>
//这种写法比较少见,没有什么应用场景:
int main01()
{
int a = 10;
int b = 20;
int c = 30;
int* arr[3] = {&a, &b, &c};
int i = 0;
for(i = 0; i < 3; i++)
{
printf("%d ", *(arr[i]));
}
return 0;
}
//常见的写法:
int main()
{
int a[5] = {1, 2, 3, 4, 5};
int b[5] = {2, 3, 4, 5, 6};
int c[5] = {3, 4, 5, 6, 7};
int* arr[3] = {a, b, c};
//通过arr把a、b、c三个数组的内容输出
int i = 0;
for(i = 0; i < 3; i++)
{
int j = 0;
for(j = 0; j < 5; j++)
{
//printf("%d ", *(arr[i] + j));
printf("%d ", arr[i][j]);//同上
}
printf("\n");
}
}
三、数组指针
1、什么是数组指针
整型指针 -> 是指向整型的指针 字符指针 -> 是指向字符的指针 ==数组指针 -> 是指向数组的指针==
int main()
{
int a = 10;
int* pa = &a;
//----------------分割线----------------
char ch = 'w';
char* pc = &ch;
//----------------分割线----------------
int arr[10] = {1,2,3,4,5};
int (*parr)[10] = &arr;
//*parr是数组指针,指向10个整型元素的数组;parr的类型:把parr去掉int(*)[10]就是parr的类型
return 0;
}
2、小例1:
💨 定义一个指针数组double* d[5] -> d是一个数组,有5个double*类型的元素,现将数组d存储
double* (*pd) [5] = &d; ==pd是一个数组指针,指向一个5个double *类型元素的数组==
3、数组名
💨 我们都知道数组名有2种特殊用法:其1,sizeof(数组名)表示求整个数组的大小;其2,&数组名表示取整个数组的地址
int arr[10] = {0}; int* p1 = arr; int (*p2)[10] = &arr;
#include<stdio.h>
int main()
{
int arr[10] = {0};
int* p1 = arr; //把数组首元素地址存储于p1,p1的类型是int*
int (*p2)[10] = &arr; //这里的p2就是指向数组的指针,这个数组有10个元素,每个元素的类型是int;也可以说指针p2的类型是int[10]
//p1和p2是相同的指向同一位置
printf("%p\n", p1);
printf("%p\n", p2);
//但是p1和p2的类型不一样,它们的意义也不一样
printf("%p\n", p1 + 1);//跳过一个整型
printf("%p\n", p2 + 2);//跳过一个数组
return 0;
}
4、数组指针的使用
💨 一般不会在一维数组上使用
#include<stdio.h>
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int (*parr)[10] = &arr;
int i = 0;
for(i = 0; i < 10; i++)
{
printf("%d ", *((*parr) + i));//*parr相当于arr,
}
return 0;
}
💨 通常是在二维数组上使用
#include<stdio.h>
void print1(int arr[3][5], int r, int c)
{
int i = 0;
int j = 0;
for(i = 0; i < r; i++)
{
for( j = 0; j < c; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
}
void print2(int(*p)[5], int r, int c)//二维数组传首地址同arr[0],这里使用数组指针来接收
{
int i = 0;
int j = 0;
for(i = 0; i < r; i++)
{
for(j = 0; j < c; j++)
{
printf("%d ", *(*(p + i) + j));
}
printf("\n");
}
}
int main()
{
int arr[3][5] = {{1,2,3,4,5}, {2,3,4,5,6}, {3,4,5,6,7}};
print1(arr, 3, 5);//通常方法
printf("------------分割线------------\n");
print2(arr, 3, 5);//数组指针
return 0;
}
5、简单梳理
👁🗨 相信看到这里,可能许多小伙伴都会懵圈了
int arr[5]; -> arr是一个整型数组,可存储5个int类型的元素 int* parr1[10]; -> parr1是一个指针数组,可存储10个int*类型的元素 int (*parr2) [10]; -> prr2是一个数组指针,指向一个10个int类型的数组 int (*parr3[10]) [5]; -> parr3是一个数组,可存储10个int( * )[5] —— (数组指针)类型的元素,且每个数组指针指向一个5个int类型的数组