C语言——指针

地址编号

概述

地址编号是内存每一个字节的编号统称。
int n = 10;
在内存分配了 4 个字节
每个进程(运行着的程序)都有寻址范围
32 位机的寻址范围时 4G,0x00 00 00 00~0xff ff ff ff.
系统会为每一个字节分配一个 32 位的地址编号。便于系统管理内存
32 位机的地址编号占 4 字节
64 位机的地址编号占 8 字节

指针和指针编号

指针:是地址编号的数据类型,强调的是类型

指针变量:数据类型为指针的变量,用于保存地址编号

注意

B b
B: 字节
b:

指针变量定义

语法

数据类型 * 变量名;
注意
数据类型 : 指针变量指向的地址中存储的数据的数据类型
1, 不同的指针只能存储对应的数据类型的地址
:
整型的指针变量,只能存放整型变量的地址
2, 如果在一行中定义多个指针变量,每个指针变量前面都需要加 * 来修饰

int *p1;
char *p2;
float *p3;
double *p4;
void *p5;
...
int nums[] = {1,2,3,4,5};
int *p6 = nums;
int *p1,*p2,*p3;

指针变量的初始化

注意
1, 当指针变量为局部变量 , 并没有为其赋初始值 , 此时因为是局部变量 , 所以系统为其赋
值为随机数 , 此时我们并不知道指针变量存储的地址是什么 . 这种指针我们称为野指针
2, 指针变量没有指向合法的地址建议初始化为 NULL, 这种指针我们称为空指针

指针运算符

&

作用:取地址

int a = 10;
int *p = &a;
printf("%p\n",p);// 此时打印的是 p 的值即 a 的地址

*

作用:取值

printf("%d\n",*p);// p 中存储的地址中的值获取

作用:改值

*p = ;
注意事项
野指针与空指针取值操作会出现段错误

类型

指针的数据类型

int *p;
char *p;

口诀

将指针变量的变量名去除,剩余的就是指针变量的数据类型

指针存储的数据的数据类型

int  *p;
char  *p;

口诀

将指针变量的变量名与最近的一个*去除,剩余的就是指针变量的存储地址对应的数据类型

作用

分析等号两边的数据类型一致

二级指针

概念

又名:指针的指针

因为指针变量的本质也是一个变量,在32位机中占4字节,在64位机中占8字节

int a=10;                     //假设此时a在栈内的地址编号为0x00 00 00 00,长度4字节

int *p=&a;                 //将a的地址赋值给变量p,此时p存储的地址为a的地址。即0x00 00 00 01,

p本身也需占用内存,其地址假设为0x00 00 00 06

int **p2=&p;                //将p的地址即0x00 00 00 06赋值给p2,p2本身也是变量,顾问也需

占用内存,其地址假设为0x00 00 00 14,该指针就是二级指针;

int ***p3=&p2;            //该指针就是三级指针

...

问题

1.二级指针使用*取出的是什么?

存储的一级指针本身的地址,不是一级指针存储的地址

int num01=10;

int num02=1;

int *p1=&num01;

int *p2=&num02;

*p1=100;

printf("num01=%d\n",num01);  

printf("num02=%d\n",num02);  

int **p3=&p1;

*p3=p2;

printf("num01=%d\n",num01);  //100

printf("num02=%d\n",num02);  //1

printf("**p3=%d\n",**p3);  //1


void与指针

void作用

1,void作为函数的返回值类型,表示没有返回值或返回值为NULL
void test()
{
for(int i = 0; i < 10; i++)
{
xxx
if(xx)
{
return;
}
}
}
2,void与指针结合称为万能指针,可以存储任何一种类型变量的地址
int num = 10;
int *p1 = &num;
char c = 'a';
char *p2 = &c;
void *p3 = &num;
void *p4 = &c;
p3 = &c;// 修改 p3 存储的地址

万能指针的作用

万能指针主要用于作为函数的形参
万能指针的注意事项
不能直接对void *p中的p直接取*,因为无法确定p的取值宽度

const与指针

常量指针

概念

指向常量的指针,本质是一个指针

作用

不能通过指针改变其指向的地址的类型,但是可以改变其存储的地址

语法

const 数据类型 *指针名

数据类型 const *指针名

示例

#include <stdio.h>
int main(int argc, char const *argv[])
{
int a = 10;
int b = 1;
// 常量指针 , 本质是指针 , 可以修改其存储的地址 , 但是无法修改其存储的地址对应
的值
//const int *p = &a;
int const *p = &a;
p = &b;// 改变 p 存储的地址
//*p = 100;// 改变 p 存储的地址对应的值 , 此处报错
return 0;
}

指针常量

概念

本质是一个常量,该指针存储的地址无法修改,但是可以修改其存储的地址对应的值

语法

数据类型 *const 指针名;

示例

#include <stdio.h>
int main(int argc, char const *argv[])
{
int a = 10;
int b = 1;
// 指针常量 , 本质是一个常量 , 不能修改其存储的地址 , 但是可以修改其存储的地址
对应的值
int * const p = &a;
//p = &b;// 不可以改变 p 存储的地址
*p = 100;// 改变 p 存储的地址对应的值
printf("a = %d\n",a);
return 0;
}

常量指针常量

概念

常量指针指向常量

语法

const 数据类型 * 指针类型;
数据类型 const * 指针名;

示例

#include <stdio.h>
int main(int argc, char const *argv[])
{
int a = 10;
int b = 1;
// 常量指针常量
//const int * const p = &a;
int const * const p = &a;
p = &b;// 不可以改变 p 存储的地址
*p = 100;// 也不可以改变 p 存储的地址对应的值
printf("a = %d\n",a);
return 0;
}

数组与指针

数组名的本质

数组名就是数组中第一个元素的地址

示例1

#include <stdio.h>
int main(int argc, char const *argv[])
{
int nums[] = {1,5,10};
printf("nums 的地址 = %p\n",nums);
printf("nums[0] 的地址 = %p\n",&(nums[0]));
int *p = nums;
printf("nums[1] = %d\n",nums[1]);// 取数组下标为 1 的元素
printf("p[1] = %d\n",p[1]);// 取数组下标为 1 的元素
//1 个步长 = 数组中存储的元素的数据类型所占的字节数
printf("*(p+1) = %d\n",*(p+1));// 将当前位置 +1 个步长 , 取的是数组下标为 1
的元素
printf("*p+1 = %d\n",*p+1);
return 0;
}

示例2

#include <stdio.h>
int main(int argc, char const *argv[])
{
char str[] = "hIc";
char *p = str;
// 此时数组中存储的元素为 char, 一个 char 的长度为 1 字节 , 顾此时 1 个步长 =1 字节
printf("%c\n",*(p+1));
printf("%c\n",*(p+2));
printf("%c\n",*(p+3));
printf("%c\n",*p+1);//*p 获取的是其地址对应的值 , 其地址的值为 h,h+1=i
printf("%c\n",(*p)+1);
return 0;
}

指针数组与数组指针

概念

数组指针(数组的指针):指向数组,本质是指针

指针数组(存储指针的数组):本质是一个数组

示例1

#include <stdio.h>
int main(int argc, char const *argv[])
{
int nums[] = {1,2,3};
// 数组指针 ( 数组的指针 , 指向数组 , 本质是指针 )
int *p = nums;
int a = 1;
int b = 2;
int c = 3;
int *p11 = &a;
int *p12 = &b;
int *p13 = &c;
// 指针数组 ( 存储指针的数组 , 本质是一个数组 )
int *p2[] = {p11,p12,p13};
return 0;
}

示例2

#include <stdio.h>
int main(int argc, char const *argv[])
{
int nums01[] = {1,2,3,4,5};
int nums02[] = {11,22,33,44,55};
int nums03[] = {111,222,333,444,555};
// 二维数组
int nums04[][5] = {
{1,2,3,4,5},
{11,22,33,44,55},
{111,222,333,444,555}
};
// 指针数组
int *ps[]={nums01,nums02,nums03};
printf("nums04[0][1] = %d\n",nums04[0][1]);
printf("ps[0][1] = %d\n",ps[0][1]);
printf("nums04[1][1] =%d\n",nums04[1][1]);
printf("(*(ps+1))[1]=%d\n",(*(ps+1))[1]);
printf("*(*(ps+1)+1)=%d\n",*(*(ps+1)+1));
return 0;
}

示例3

#include <stdio.h>
int main(int argc, char const *argv[])
{
// char strs[][50] = {"GaoLei","WangChenHui","YueZheng"};
char *strs[] = {"GaoLei","WangChenHui","YueZheng"};
printf("strs[0] = %s\n",strs[0]);
printf("strs[1] = %s\n",strs[1]);
printf("strs[2] = %s\n",strs[2]);
printf("*(strs+0) = %s\n",*(strs + 0));
printf("*(strs+1) = %s\n",*(strs + 1));
printf("*(strs+2) = %s\n",*(strs + 2));
printf("(*(strs + 0))+3 = %s\n",(*(strs + 0))+3);
printf("(*(strs + 0))[3] = %c\n",(*(strs + 0))[3]);
return 0;
}

示例4

#include <stdio.h>
int main(int argc, char const *argv[])
{
// char strs[][50] = {"GaoLei","WangChenHui","YueZheng"};
char *strs[] = {"GaoLei","WangChenHui","YueZheng"};
printf("strs[0] 的地址 =%p\n",&strs[0]);
printf("strs 的地址 =%p\n",strs);
printf("&strs 的地址 =%p\n",&strs);
char * p;
p = strs;
//char **p2 = &p;
//char **p2 = &strs;
char **p2 = strs;
printf("*p2 = %s\n",*p2);
printf("**p2 = %c\n",**p2);
printf("*(p2+1) = %s\n",*(p2+1));
printf("*(p2+2) = %s\n",*(p2+2));
printf("(*(p2+1))+4 = %s\n",(*(p2+1))+4);
return 0;
}

函数与指针

函数名的本质

函数名的本质上就是函数在代码区存储的首地址

函数指针

作用:

记录函数的地址

语法:

返回值类型 (*指针名称)(指向的函数的形参列表的数据类型) = 函数名;
注意 :
形参列表的数据类型可有可无
函数指针调用函数
指针名 ( 实参列表 );
变量名 = 指针名 ( 实参列表 );

示例

#include <stdio.h>
extern void add(int a,int b);
extern void sub(int a,int b);
extern void test(void (*p)(int,int));
int main(int argc, char const *argv[])
{
printf("main 函数的地址 =%p\n",main);
int (*p)(int,char *[]) = main;
// 返回值类型 (* 指针名称 )( 指向的函数的形参列表的数据类型 ) = 函数名 ;
void (*p2)(int,int) = add;
// 函数指针调用函数
// 指针名 ( 实参列表 );
// 变量名 = 指针名 ( 实参列表 );
// p2 = sub;
p2(1,2);
test(p2);
return 0;
}
void test(void (*p)(int,int))
{
p(10,12);
}
void add(int a,int b)
{
printf("%d+%d=%d\n",a,b,a+b);
}
void sub(int a,int b)
{
printf("%d-%d=%d\n",a,b,a-b);
}

指针作为形参

#include <stdio.h>
extern void showArray(int nums[],int len);
int main(int argc, char const *argv[])
{
int nums[] = {1,2,3,4,5};
showArray(nums,5);
return 0;
}
void showArray(int *nums,int len)
{
for (int i = 0; i < len; i++)
{
// printf("%d\t",nums[i]);
printf("%d\t",*(nums+i));
}
printf("\n");
}

指针作为返回值

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
// extern int* getNums();
extern void getNums(int nums[],int len);
int main(int argc, char const *argv[])
{
srand(time(NULL));
// int *p = getNums();
// for (int i = 0; i < 10; i++)
// {
// printf("%d\t",p[i]);
// }
// printf("\n");
int nums[10] = {0};
getNums(nums,10);
for (int i = 0; i < 10; i++)
{
printf("%d\t",nums[i]);
}
printf("\n");
return 0;
}
// int* getNums()
// {
// static int nums[10] = {0};
// for (int i = 0; i < 10; i++)
// {
// nums[i] = rand() % 100;
// }
// return nums;
// }
void getNums(int nums[],int len)
{
for (int i = 0; i < len; i++)
{
nums[i] = rand() % 100;
}
}

  • 23
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值