当前位置: 首页 > news >正文

C语言基础:指针(三)

字符指针常见错误
#include <stdio.h> ​ int main(int argc, char **argv) { //char *p = "hello"; // hello 在内存中,只用一份,只能读取,不能修改 char p[] = "hello"; // char [] 开辟空间,会把hello字符串常量复制一份,给数组。 ​ printf("%s\n", p); *(p + 0) = 'e'; // 如果是指针,操作是错误,不能修改常量 p[0] = 'e'; // 如果是数组,操作是对的,修改的是,数组里的内容,不是字符串常量 printf("%s\n", p); return 0; } ​

函数指针,指针函数

  1. 指针函数,函数的返回值是 指针类型 。
char *strcpy(char *dest, const char *src); strcpy 这个函数的返回值,就是一个指针。 成功,指针指向 dest。 ​

1), 不能返回,是局部作用域的指针。

2) ,希望函数,可以连续调用。 在同一个语句里面。 strcpy(str1,strcpy(str3,str2));

3)希望返回一端内存区域 (数组,堆空间)。

  1. 函数指针

    前面介绍的指针,基本都是指数据。

    函数指针 ,指向一个函数。本质,指针变量;

    函数名,是地址值。里面储存的代码,对数据进行加减乘除操作的。

    目的,

    避免代码的重复。 方便后期代码的扩展。函数功能的解耦合。

,==回调函数==, 一个函数被当作参数 ,传递给另外一个函数。 被传递这个参数(函数指针,回调函数);被动调用。主调函数只是传参(函数)。

语法 int add(int a, int b) // int (*) (int,int) { return a + b; } ​ int main(int argc, char **argv) { int (*p)(int, int) = add; // p 函数指针。 add 不能写成add(), 不是对add函数的调用 ​ int a = 10; int b = 20; int ret = 0; ret = add(a, b); printf("add() is %d\n", ret); ret = p(a, b); // 通过函数指针 对函数的调用 printf("p() is %d\n", ret); ​ return 0; }
int div3(int num) // div3 -> int (*) (int) { return 0 == num %3; } int div5(int num) // div3 -> int (*) (int) { return 0 == num %5; } // int (*fun) (int) 函数指针 void find_num(int* a,int size, int (*fun) (int) ) { ​ for(size_t i=0;i<size;i++) { if( fun(a[i])) // if( div5(a[i])) { printf("%d\n",a[i]); } } } int main(int argc, char **argv) { int a[10]={0}; fill_array(a,10); //find_num3(a,10); find_num(a,10,div5); // 传递函数名给 find_num ​ return 0; } ​
typedef 关键字

取别名, 给数据类型取别名

1 普通数据类型 去别名

typedef 老数据类型名 新数据类型名 typedef unsigned char u8; typedef unsigned short u16; typedef char s8; int main(int argc, char **argv) { u8 a; // unsigned char u16 b; // unsigned short s8 c; // char ​ return 0; }
  1. 简化函数指针的写法

PFUN 是一个类型名 typedef int* (*PFUN)(int ,int ,char* ); // int* func(int a,int b ,char* c) // int* (*)(int ,int ,char* ) // { // return NULL; // } ​ // int func2(int a,int b, int* (*pfun)(int ,int ,char* )) // { ​ // return 0; // } ​ int* func(int a,int b ,char* c) // int* (*)(int ,int ,char* ) { return NULL; } ​ int func2(int a,int b, PFUN pfun) // int a; { char str[]={0}; pfun(1,2,str); return 0; }

3.和结构体有关,晚些介绍

指针数组,数组指针

指针数组

本质,是一个数组。 数组中数据元素是 指针。指针是字符类型指针,用的多。

数据类型 * 数组名[整形常量]; ​ int * a[4];
char* a[4]={NULL}; char * b[5]={"hello","ok","how","are","you"}; // 指针指向了字符串常量去,只可以读取,不可以修改
​ char str[8][100]={"hello","ok","how","are","you"}; char *str3[5]={str[0],str[1],str[3]};// 指针指向了数组,可以读取,可以修改

存放字符串使用字符数组,操作字符串使用指针。

存放多个字符串使用二维字符数组(多个字符串的话)。操作字符串数组使用 指针数组。

数组指针

对一维数组名执行 取地址操作(&) , 地址值 不变, 类型升级为指向整个数组的指针

对数组指针 执行 解引用操作 (*) , 地址值 不变, 类型降为指向第一个元素的指针

应用:

1) 需要和二维数组配合使用

2) 把二维数组作为参数的时候,在定义被调函数,需要声明 参数的数据类型,会用到。

#if 0 int a[5] = {1, 2, 3, 4, 5}; // int []--> int * ​ printf("a addr %p\n", a); ​ printf("a[0] addr %p\n", &a[0]); printf("a[1] addr %p\n", &a[1]); printf("a[2] addr %p\n", &a[2]); printf("*a addr %d\n", *a); // int printf("a[0] addr %d\n", a[0]); // int printf("*(a+1) addr %d\n", *(a + 1)); // int printf("a[1] addr %d\n", a[1]); // int printf("a+1 addr %p\n", a + 1); // int * printf(" &a %p\n", &a); // 数组指针 printf("&a+1 %p\n", &a + 1); int(*p)[5] = &a; // int (*p)[5] 数组指针 int* p[5] // int * p1[5] =&a; #endif int array2[4][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; int(*p2)[4] = array2; ​ printf("array2 is addr%p\n", array2); // int [4][4] -> int (*)[4] +1 ->16byte printf("array2[0] is addr%p\n", array2[0]);// int * +1 4byte printf("array2[0][0] is addr%p\n", &array2[0][0]);// int * +1 4byte printf("array2[0][0] is addr%d\n", array2[0][0]); // int ​ printf("a[1][2] %d\n",array2[1][2]); // printf("a[1][2] %d\n",*(array2[1]+2)); printf("a[1][2] %d\n",*(*(array2+1)+2)); ​ printf("p2[1][2] %d\n",p2[1][2]); printf("p2[1][2] %d\n",*(p2[1]+2)); printf("p2[1][2] %d\n",*(*(p2+1)+2)); ​ printf("&a[0] %p\n",&array2[0]); printf("&a[1] %p\n",&array2[1]); printf("p2 %p\n",p2); printf("p2+1 %p\n",p2+1); ​ int array2[4][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; array2 类型 -》 指针 -》 int [4][4] int(*)[4] 列是4 +1 sizeof(int) *4(列) array2[0] -- > 指针 -》 int * 第一行的首元素的地址 == &array2[0][0] array2[0][0] - > int -> 数据 int(*p2)[4] = array2; p2 -> 类型 int(*)[4] +1 sizeof(int) *4(列) p2[0] -> 类型 int* 第一行的首元素的地址 == &array2[0][0] p2[0][0] -> int -> 数据 p2[1] = > *(p2+1) 下标运算符 和 解引用运算符的关系。

二级指针

二级指针:本质还是指针,是一个指针变量的地址。

int **指针名称; ---》保存整形指针的指针 char **指针名称;---》保存字符型指针的指针

C语言中主要有两个二级指针的使用场景:

  1. 想要在被调函数中修改主调函数中的指针变量,实参需要传递该指针变量的地址;形参用二级指针接收。

  2. 指针数组的数组名,是一个二级指针,实参传递指针数组的数组名时,形参可以用二级指针接收。

char *str[3] = {"hello", "world", "how"}; str[0] ---> char * --->保存了字符串常量"hello"的首地址 str ===> &str[0] ===> char ** 二级指针
  • 值传递:无法在被调中修改主调中的变量,只能使用该变量

  • 指针传参:可以在被调中修改主调中定义的变量,也可以使用该变量

  • 值传递:恰好传递的值是一个指针变量,无法在被调用修改主调中定义的指针变量,可以使用该指针变量。

  • 指针传参:可以在被调函数中可以修改主调函数中定义的指针变量,也可以使用该变量

指针函数

指针函数:本质是函数,具有指针类型返回值的函数称为指针函数。

指针函数能返回什么指针?

  1. 局部变量的地址不能被返回(局部变量,局部数组)

    char str[32] = {"hello world"}; char *str = "hello world";
  2. 具有静态生命周期的变量的地址可以被返回。

    1. static修饰的静态变量地址。

    2. 全局变量的地址。

  3. 可以返回字符串常量的地址。

    char *pstr = “hello world”;
  4. 可以返回通过参数传递给该函数的地址。

    char *strcpy(char *dest, const char *src);
  5. 可以返回堆区申请且没有被释放的空间地址。

函数指针

函数指针:本质是指针,指向函数的指针。

函数:函数的函数名,为函数的入口地址。

函数指针语法:

  1. 定义函数指针

函数声明: int fun(int, int); int *pfun(int , int ); ​ 函数指针: int (*pfun)(int , int ); 定义了一个函数指针变量,该指针变量在内存占8字节,该函数指针可以指向一个具有int返回值,两个int类型的参数的函数。 ​ char *(*pfun)(char *); ​ 总结: 返回值类型 (*指针名称)(形参表);
  1. 函数指针初始化

int (*pfun)(int, int) = NULL;
  1. 函数指针赋值

int add(int num1, int num2) {} ​ int (*pfun)(int, int) = NULL; pfun = add;
  1. 函数指针调用函数

函数名(实参表); ​ 函数指针名称(实参表);
  1. 函数指针的应用

    • 回调函数

      将函数作为某个函数的参数传递,传递的函数称为回调函数。

      主要为了降低代码的耦合度(关联度),减少重复代码。

http://www.jsqmd.com/news/1337345/

相关文章:

  • 从零构建企业级数据治理体系:DataArts Studio核心模块与实战路径解析
  • 模拟CMOS单级放大器设计:从共源到共源共栅的电路直觉与工程权衡
  • 2026年8月台州太阳能排风扇/浙江屋顶排风扇厂家厂家推荐_浙江海天机械有限公司 - 品牌宣传支持者
  • 钉钉审批流实战:从设计到上线的全流程指南与避坑经验
  • 采购四川比较好的菱形勾花网热门厂家怎么选才不踩坑 - 品牌优推
  • MacBook新手指南:从系统设置到开发环境配置的完整上手教程
  • 从开环到闭环:基于PID算法与灰度传感器的智能小车巡线控制实践
  • Linux审计框架auditd实战:从内核事件捕获到高级规则定制
  • LangChain集成百度千帆SDK:从零构建可落地的LLM应用实战指南
  • 论文降AI率免费额度只有1000字,先拿哪一段去试才不浪费?
  • 长春空气能选购门店哪家专业:【芬尼】寒地定制 - 18002239949
  • AI驱动智能合约安全审计:从Claude实战到未来攻防范式变革
  • 2026年8月四川防腐储罐/成都衬塑储罐厂家怎么选_成都臻沃通科技有限公司 - 行业平台推荐
  • 【C 语言入门第 15 天】共用体、枚举、位运算核心知识点梳理
  • Mac上SVN配置与开发实战:从工具链选型到高效工作流
  • 重庆菜市场商户采购指南,津白适合需要稳定大批量供货
  • 利用Cadence Allegro SKILL脚本实现PCB设计自动化:零件导出与引脚统计
  • 寻找河北纸箱印刷机供应商怎么选看这几点就够了 - 品牌优推
  • 2026年AI模型选型实战:从API到自托管对比
  • Inkling-Small:MoE架构如何以12B激活参数实现高效多模态推理
  • 汽车电子SBC休眠唤醒实战:TLE9262精准功耗管理与调试指南
  • 龙井镇附近的衣帽间定制热门厂家怎么选更靠谱? - 品牌优推
  • 抖音批量下载终极指南:如何高效获取无水印视频与完整元数据
  • 物理不可克隆函数(PUF)原理与应用:从硬件指纹到安全密钥的实战解析
  • i.MX6ULL HAB安全启动实战:从PKI构建到镜像签名与熔丝烧录
  • HTML5语义化标签与文档结构详解:从基础到实战的网页骨架构建指南
  • SPICE磁滞建模实战:从Jiles-Atherton模型到工程调试技巧
  • 2026年8月成都钢衬pe储罐/碳钢衬四氟储罐行业公司推荐_成都臻沃通科技有限公司 - 品牌宣传支持者
  • G-Helper架构解析:华硕笔记本轻量级控制方案的技术实现
  • 2026 年现阶段荆州正规的学校护栏工厂推荐几家,放学铃响的最后30秒,那道不起眼的东西竟救了整层楼的孩子。-昊宇丝网 - 行业严选官