- 指针就是地址
- 指针是一种数据类型,是一种保存地址的数据类型
- int是一种数据类型,是一种保存整数的数据类型 1 2 3 4
- float是一种数据类型,是一种保存浮点数的数据类型 3.14
- 内存分配的最小单位是字节,每一个字节都有一个编号,我们把整个编号就叫做地址
-
- 地址的本质:内存单元的编号
-
- 指针:指针就是地址
-
- 指针的本质:内存单元的编号
- int a;
-
- float b;
-
- 指针变量:专门原来保存地址(内存单元的编号)的变量
- 存储类型 数据类型 *指针变量名;
- int * p;
- 数据类型表示本指针变量所指向的变量的数据类型
- 存储类型表示本指针变量所指向的变量的存储类型
- 指针变量名是*后面的内容,*只是说明定义的是一个指针变量
- 只能指向相同数据类型的变量
- int * p;
- 存储类型:auto、static、extern、register
- 数据类型:指针所执行的数据类型 //int
- 指针数据类型(去掉指针变量名):数据类型 * //int*
- *在c语言中有3种用法:
- 1、作为双目运算符,表示乘法 3*4
- 2、在定义变量的时候使用,表示指针这种数据类型
- 3、作为单目运算符,表示取值 *p(取指定变量p所存储的地址) 通过指针间接访问指针所指向的对象
- 在C语言中,变量的地址是由编译系统分配的,用户不知道变量的具体位置。C语言中提供了地址运算符“&”来表示变量的地址,其一遍形式为 &变量名;
- int i,*p;
- p = &a;



注意:
- 1、指针的指向是可以改变的
- 2、给指针赋值时,要注意数据类型的匹配
- &是取地址运算符 *(地址)是取值运算符
- 3、&和*互为逆运算,可以相互抵消,正和负的关系
- 4、&为引用,*为解引用
在32OS系统中,所有的指针都占4个字节

在64OS系统中,所有的指针都占8个字节

思考
- 1、什么是指针
- 指针是一种数据类型,是一种保存地址的数据类型(内存单元的编号)
- 2、什么是地址
- 内存单元的编号
- 3、什么是指针变量
- 专门用来保存指针的变量
- 4、如何定义一个指针变量
- 存储类型 数据类型 * 指针变量名
- 5、如果给指针变量赋值
- p = &a
- 6、赋值之后可以做什么呢
- 修改、操作变量a
- 空指针:int * p = NULL;
-
- 没有指向的指针(值为0的指针,就认为该指针没有指向)
-
- 注意:0号地址禁止操作(一旦操作会出现段错误//Segmentation fault (core dumped))非法访问内存空间。

要操作必须改变空指针的指向

- int * p;
-
- 不知道指向哪里的指针
-
- 局部变量没有初始化的时候,其值为随机值
-
- 局部指针变量没有初始化,就成了野指针
-
- 空指针操作不会出问题,野指针操作可能会出问题(随机值)//不清楚具体指向,修改取值会报错
-
- 如何避免野指针的出现?初始化为NULL

Linux中调试使用调试器gdb
- 编辑器:vim
- 编译器:gcc
- 调试器:gdb
调试步骤
- (1)编译程序的时候添加 "-g"参数
- gcc -g error.c -o error
- (2)启动gdb调试器
- gdb 可执行文件的名字 (gdb error)
- (3)设置断点
- b main
- b 行号
- (4)运行
- r
- (5)其它参数
- n(next):下一步,不进入子函数
- s(step):下一步,进入子函数
- p(printf) a(要打印的值)
- c(continue):可以直接跳出循环,执行下一步
- q(quit):退出
编写一子函数,实现两个数的交换


- 值传递:以下类型变量作为函数参数传递,包括基本数据类型变量(例如int、char、double等)、结构体类型变量。被调函数中对形参值的修改,不影响主调函数中的实参值。
-
- 值传递:类似物体的克隆,被调函数操作克隆的物体,主调函数操作源物体。本质是形参的地址空间与实参的地址空间不同。
- include
-
- void swp(int * m, int * n);
-
- int main(void)
- {
- int a = 1;
- int b = 2;
- swp(&a,&b);
- printf("%d\n",a);
- printf("%d\n",b);
- return 0;
- }
- void swp(int * m, int * n)
- {
- int tmp =0;
- tmp = *m;
- *m = *n;
- *n = tmp;
- }

- 地址传递:以下类型变量作为函数参数传递,包括数组名、指针或地址。被调函数中对形参值的修改,会影响主调函数中的实参值。
-
- 地址传递:类似物体的移动,两个函数先后操作同一个物体。本质是形参的地址空间与实参的地址空间相同。
const:只读
用来修饰变量,使用const修饰的变量只能读,不能被修改(未修改存储位置,仍在栈区)
- int a = 10;//存放在栈区
- const int a = 10;//
判断const修饰的变量是否在常量区

const修饰的指针:
- 指针变量:
- (1)指针常量: 指针的指向不能发生改变
- int * const p = NULL;//值可改,指向不可改
- (2)常量指针: 指针所指向的内容不能被修改
- int const *p = NULL;//指向可改,值不可改
- (3)值和指向都不能修改
- const int * const p = NULL;//值和指向都不能被修改

- 二级指针:指针的指针
-
- 二级指针的内存空间存放的是一级指针变量的地址
- 一级指针: 存储类型 数据类型 *指针变量名;
- 数据类型:指针所指向的数据类型
- 一级指针:列指针,*一级指针:取值
- 二级指针:行指针,*二级指针:变为一级指针(列指针、一维数组名)
- 二级指针的定义:
- 存储类型 数据类型 **指针变量名;
- 二级指针的数据类型:数据类型 **
- p = &a;
- pp = &p;
- pp = &&a;//不能对a的地址常量取地址


案例
- (1).若有语句int *point, a=4;point=&a;下面均代表a的地址的一组选项是(D)
- A. a, point,*&a B. &*a, &a,*point
- C. &point, *&point, &a D. &a, &*point, point
- (2).已有定义int k=2; int*ptr1,*ptr2;且ptr1和ptr2均已指向变量k,下面不能正确执行赋值语句的
- 是(B)
- A. k=*ptr1+*ptr2; B.ptr2=k;
- C.ptr1=ptr2; D. k=*ptr1*(*ptr2);
- 1、指针指向的数据类型就是将变量名和*(一个)去掉,剩下的就是指针所指向的数据类型
- int *p; // int
- int **p; //int *
- int ***p;//int **
- 2、指针的数据类型就是就变量名去掉,剩下的就是数据类型
- int *p;//int *
- int **p;//int **
- int ***p;//int ***
- 3、*p所能访问的空间大小,有p指向的数据类型来决定
- char *p;//*p所能访问的内存空间的大小为1byte
- int *p;//*p所能访问的内存空间的大小为4byte
- int **p;//**p所能访问的空间的大小为4byte
- int a[5] = {0};
- 1-------数组的输入
- 2-------数组的输出
- 3-------求数组中的次大值
- 4-------排序
- -1 -----exit


- #include
- #define N 5
- #include
-
- void menu();
- void input();
- void output();
- void sub();
- void swap();
- void quit();
-
- int main(void)
- {
- int fun = 0;
- int a[N] = {0};
- while(1)
- {
- menu();
- printf("请选择功能");
- scanf("%d",&fun);
- switch(fun)
- {
- case 1:
- input(a);
- break;
- case 2:
- output(a);
- break;
- case 3:
- sub(a);
- break;
- case 4:
- swap(a);
- break;
- case -1:
- quit();
- }
- }
-
- return 0;
- }
- void menu()
- {
- printf("功能菜单\n");
- printf("1-数组的输入\n");
- printf("2-数组的输出\n");
- printf("3-求数组中的次大值\n");
- printf("4-排序\n");
- printf("-1-exit\n");
- }
- //输入
- void input(int * a)
- {
- for(int i = 0; i
- {
- scanf("%d",&a[i]);
- }
- }
- //输出
- void output(int * a)
- {
- for(int i = 0; i
- {
- printf("%d\n",a[i]);
- }
- }
- //次大值
- void sub(int * a)
- {
- int i,max,mid;
- for(i = 0;i<5;i++)
- {
- if(a[i]>max)
- {
- mid = max;
- max =a[i];
- }
- else if(a[i]>mid&&a[i]
- {
- //另一种情况 arr[i]在两者之间*/
- mid = a[i];
- // 把arr[i]赋给mid
- }
- }
- printf("次大值:%d\n",mid);
-
- }
- //排序
- void swap(int * a)
- {
- int i,j,tmp = 0;
- for(i=1;i
- {
- for(j=0;j
- {
- if(a[j]>a[j+1])
- {
- tmp=a[j];
- a[j]=a[j+1];
- a[j+1]=tmp;
- }
- }
- }
- }
- //退出
- void quit()
- {
- exit(0);
- }
-
相关阅读:
1331. 数组序号转换 : 简单模拟题
redis问题:三种集群——主从、哨兵、cluster集群;16384槽等
数据库相关概念复习--个人复习使用
集合—Collections工具类
Go单体服务开发最佳实践
以太坊实现、语言模型应用与实用工具 | 开源日报 0817
Flutter常见UI组件使用
关于pytorch nn.KLDivLoss()损失计算loss值为负数的原因
MySQL数据库备份与恢复 未完成版。。。
网络安全-信息收集简介
-
原文地址:https://blog.csdn.net/m0_58540923/article/details/134235600