C语言进阶--指针

指针

  • 1. 字符指针
  • 2. 指针数组
  • 3. 数组指针
    • 3.1. 数组指针的定义
    • 3.2. &数组名VS数组名
    • 3.3. 数组指针的使用
  • 4. 数组参数,指针参数
    • 4.1. 一维数组传参
    • 4.2. 二维数组传参
    • 4.3. 一级指针传参
    • 4.4. 二级指针传参
  • 5. 函数指针
    • 5.1. 函数指针的地址
    • 5.2. 函数指针的定义和调用
    • 5.3. 有趣的代码
  • 6. 函数指针数组
  • 7. 指向函数指针数组的指针
  • 8. 回调函数
    • 8.1 qsort--数组排序

1. 字符指针

int main()
{char ch = 'w';char* pc = &ch;//pc为字符指针,指向char**pc = 'w';return 0;
}
#include <stdio.h>int main()
{const char* p1 = "abcdef";//p1存放的是首元素a的地址const char* p2 = "abcdef";char arr1[] = "abcdef";char arr2[] = "abcdef";if (p1 == p2){printf("p1==p2\n");}else{printf("p1!=p2\n");}if (arr1 == arr2){printf("arr1 == arr2\n");}else{printf("arr1 != arr2\n");}return 0;
}

2. 指针数组

  • 指针数组: 是数组,是用来存放指针的数组
	int arr[10];//整型数组char ch[5];//字符数组int* arr[6];//存放整型指针的数组char* arr[5];//存放字符指针的数组
#include<stdio.h>int main()
{int arr1[] = { 1,2,3,4,5 };int arr2[] = { 2,3,4,5,6 };int arr3[] = { 3,4,5,6,7 };int* parr[3] = { arr1, arr2, arr3 };for (int i = 0; i < 3; i++){for (int j = 0; j < 5; j++){printf("%d ", *(*(parr + i) + j));}printf("\n");}//*(parr[i]+j)//*(p+i) <==> p[i]return 0;
}

3. 数组指针

3.1. 数组指针的定义

数组指针: 是指针,指向数组的指针.
整形指针,指向整型的指针.int*
字符指针,指向字符的指针.char*

	int* p1[10];	//p1是指针数组int (*p2)[10];		//p2是数组指针,指向int [10};//(指向一个数组,有10个元素,每个元素都是int)
  • 注意:[ ]的优先级要高于*号的,所以必须加上()来保证p先和*结合

3.2. &数组名VS数组名

数组名通常表示的都是数组首元素地址, arr<==>&arr[0]
但是有2个例外:
1.sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小.
2.&数组名,这里的数组名表示的依然是整个数组,所以&数组名取出的是整个数组的地址.

	int arr[10] = {0};int (*p)[10] = &arr;printf("%p\n",&arr[0]);printf("%p\n",arr);//数组中首个元素的地址printf("%p\n",arr+1);//数组中第2个元素的地址 ,arr[1]printf("%p\n",&arr);//取出的是整个数组的地址,打印的为整个数组的首个元素地址printf("%p\n",&arr+1);//跳过一整个数组后的地址

3.3. 数组指针的使用

char* arr[5] = {0};char* (*pc)[5] =&arr;//把数组arr的地址赋值给数组指针变量p
#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)
{int i = 0;for (i = 0; i < r; i++){int j = 0;for (j = 0; j < c; j++){printf("%d ", *(*(p + i) + j));}printf("\n");}
}int main()
{int arr[3][5] = { 1,2,3,4,5,6,7,8,9,10 };int* (*p)[5] = arr;int r = 3;int c = 5;print1(arr, r, c);printf("\n");print2(arr, r, c);//数组名arr,表示首元素的地址//二维数组的首元素是二维数组的第一行//这里传递的arr,相当于一维数组的地址,//用数组指针来接收return 0;
}
int arr[5];
//一维数组,又5个元素,元素类型为intint *parr1[10];
//parr1为数组,有10个元素,元素类型为int*int (*parr2)[10];
//parr2为数组指针,指向有10个元素,类型为int的数组int (*parr3[10])[5];
//parr3为存放数组指针的数组,有10个元素,元素类型为指向int类型5个元素的数组

4. 数组参数,指针参数

4.1. 一维数组传参

#include <stdio.h>
void test(int arr[])//ok
{}
void test(int arr[10])//ok
{}
void test(int* arr)//ok--首元素地址
{}
void test2(int* arr[20])//ok
{}
void test2(int** arr)//ok--首元素地址
{}
int main()
{int arr[10] = { 0 };int* arr2[20] = { 0 };test(arr);test2(arr2);
}

4.2. 二维数组传参

  • 总结:二维数组传参,函数形参的设计只能省略第一个[]的数字。
    因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素。
void test(int arr[3][5])//ok
{}
//void test(int arr[][])//err--第1个可以不填,其余必须填
//{}
void test(int arr[][5])//ok
{}
void test(int* arr)//err
{}
void test(int* arr[5])//err
{}//int* int* int* int* int*
void test(int(*arr)[5])//ok
{}//指针指向: int int int int int
void test(int** arr)//err
{}//指向int*
int main()
{int arr[3][5] = { 0 };test(arr);//arr首行地址,int arr[5],{int int int int int }
}

4.3. 一级指针传参

#include <stdio.h>
void print(int* p, int sz)
{int i = 0;for (i = 0; i < sz; i++){printf("%d\n", *(p + i));}
}
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9 };int* p = arr;//首元素地址 int*int sz = sizeof(arr) / sizeof(arr[0]);//一级指针p,传给函数print(p, sz);return 0;
}
  • 如果函数参数部分是int* p
void print(int* p)
{}
int a=0;
print(&a);//&a--a的地址,int *int* ptr = &a;
print(ptr);//ptr的类型:int*int arr[10]={0};
print(arr);
//arr表示首元素地址,int*

4.4. 二级指针传参

#include <stdio.h>
void test(int** ptr)
{printf("num = %d\n", **ptr);
}
int main()
{int n = 10;int* p = &n;int** pp = &p;test(pp);//int** test(&p);//对int*取地址,int**return 0;
}
  • 如果函数参数部分是char** p
void test(char** p)
{}
int main()
{char c = 'b';char* pc = &c;char** ppc = &pc;char* arr[10];test(&pc);//对char*取地址,char**test(ppc);//char**test(arr);//对首元素char* 取地址,char**return 0;
}

5. 函数指针

  • 函数指针 - 指向函数的指针

5.1. 函数指针的地址

#include <stdio.h>
void test()
{printf("hehe\n");
}
int main()
{printf("%p\n", test);//013211DBprintf("%p\n", &test);//013211DBreturn 0;
}

5.2. 函数指针的定义和调用

int test(const char* str)
{return 0;
}
int main()
{	//函数指针 int (*pf)(const char*) = test;//pf先和* 结合,说明pf是指针,指针指向一个函数,//函数参数为const char*,返回值类型为int//调用函数(*pf)("abc");//调用函数//pf存的是函数地址pf("abc");//okreturn 0;
}

5.3. 有趣的代码

  • 代码1
(*(void (*)())0)();//void (*)()
//函数指针类型
//(函数指针类型)0--强制类型转换
//调用0地址处的这个函数 
//函数调用,调用的是0作为地址处的函数.
  • 代码2
void (* signal( int, void(*)(int) ))(int);void(*)(int) 函数指针,参数类型int,无返回值signal ( int, void(*)(int))  
void (*                             )(int);
signal函数的第一个参数类型为Int,第二参数的类型为函数指针,
signal函数指针,返回值为 函数指针void(* )(int);

6. 函数指针数组

  • 函数指针是地址,函数也是地址

int (*pf)(int,int) = %Add;
int (*pf)(int,int) = Add;
(*pf)(2,3);//调用函数
pf(2,3);//调用函数
  • 函数指针数组: 存放函数指针的数组
int(*pfArr[4])(int,int);
//pfArr先于[4]结合,是数组,存放的是函数指针类型
//   int (* )(int,int)--函数指针
  • 函数指针数组–计算器
#include <stdio.h>int Add(int a, int b)
{return a + b;
}int Sub(int a, int b)
{return a - b;
}int Mul(int a, int b)
{return a * b;
}int Div(int a, int b)
{return a / b;
}int main()
{int input = 0;int a = 0;int b = 0;int (*pf[5])(int, int) = {0,Add,Sub,Mul,Div};do{printf("-----------------------\n");printf("-----1.add   2.sub-----\n");printf("-----3.mul   4.div-----\n");printf("-----0.exit       -----\n");printf("-----------------------\n");printf("请选择:>");scanf("%d", &input);if (input >= 1 && input <= 4){printf("请输入操作数:>");scanf("%d %d", &a, &b);printf("%d\n", pf[input](a, b));}else if (input == 0){printf("退出!\n");}else{printf("输入不合法!\n");}} while (input);return 0;
}

7. 指向函数指针数组的指针

  • 指向函数指针数组的指针,是一个指针
  • 指针指向一个数组, 数组的元素都是函数指针
void (*(*ppfunArr)[5])(const char*);(*ppfunArr)--指针
指向 void (* [5])(const char*)类型的函数指针数组

8. 回调函数

  • 通过函数指针调用的就是回调函数(函数指针,作为函数的参数)
  • 回调函数不是由该函数的实现方直接调用,
    而是在特定的事件或条件发生时由另外的一方调用的,
    用于对该事件或条件进行响应。

8.1 qsort–数组排序

void qsort (void* base, //待排序的数组size_t num,//数组的个数size_t size,//每个元素的大小(字节)int (*compar)(const void*,const void*));//比较函数
  • qsort–对int数组排序
#include <stdio.h>
#include <stdlib.h>int compare(const void* a, const void* b)
{return (*(int*)a - *(int*)b);
}int main()
{int arr[] = { 23,12,34,25,66,18 };int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]), compare);int i = 0;for (i = 0; i < sz; i++){printf("%d ", arr[i]);}//12 18 23 25 34 66return 0;
}
  • qsort–对结构体排序
#include <stdio.h>
#include <string.h>
#include <stdlib.h>struct Stu
{char name[20];int age;
};int cmp_by_name(const void* e1, const void* e2)
{return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);//return strcmp((*((struct Stu*)e1)).name, (*((struct Stu*)e2)).name);
}int cmp_by_age(const void* e1, const void* e2)
{return (((struct Stu*)e1)->age - ((struct Stu*)e2)->age);
}int main()
{struct Stu s[] = { {"zhangsan",12},{"lisi",24},{"xiaowang",7} };int sz = sizeof(s) / sizeof(s[0]);//qsort(s, sz, sizeof(s[0]), cmp_by_name);qsort(s,sz,sizeof(s[0]),cmp_by_age);int i = 0;return 0;
}
    1. 使用回调函数,模拟实现qsort(采用冒泡的方式)
    1. 知道qsort怎么使用回调函数实现的通用
#include <stdio.h>
#include <string.h>struct Stu
{char name[20];int age;
};int cmp_by_name(const void* e1, const void* e2)
{return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);//return strcmp((*((struct Stu*)e1)).name, (*((struct Stu*)e2)).name);
}int cmp_by_age(const void* e1, const void* e2)
{return (((struct Stu*)e1)->age - ((struct Stu*)e2)->age);
}int cmp_int(const void* a, const void* b)
{return (*(int*)a - *(int*)b);
}void Swap( void* e1,  void* e2,int width)
{int i = 0;for (i = 0; i < width; i++){char tmp = *((char*)e1 + i);*((char*)e1 + i) = *((char*)e2 + i);*((char*)e2 + i) = tmp;}
}void bubble_sort(void* arr,int sz,int width,int (*cmp)(void*,void*))
{int i = 0;int j = 0;//趟数for (i = 0; i < sz - 1; i++){//每趟int flag = 1;for (j = 0; j < sz - 1 - i; j++){if (cmp((char*)arr+width*j,(char*)arr+width*(j+1))>0){flag = 0;Swap((char*)arr + width * j, (char*)arr + width * (j + 1),width);}}if (flag == 1){break;}}
}int main()
{//int arr[] = { 23,12,34,25,66,18 };//int sz = sizeof(arr) / sizeof(arr[0]);//bubble_sort(arr, sz, sizeof(arr[0]), cmp_int);bubble_sort(arr, sz);struct Stu s[] = { {"zhangsan",12},{"lisi",24},{"xiaowang",7} };int sz = sizeof(s) / sizeof(s[0]);int width = sizeof(s[0]);bubble_sort(s, sz, width, cmp_by_name);//bubble_sort(s, sz, width, cmp_by_age);return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/832365.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VTK —— 二、教程七 - 对点云进行操作(按下r键切换选取或观察模式)(附完整源码)

代码效果 本代码编译运行均在如下链接文章生成的库执行成功&#xff0c;若无VTK库则请先参考如下链接编译vtk源码&#xff1a; VTK —— 一、Windows10下编译VTK源码&#xff0c;并用Vs2017代码测试&#xff08;附编译流程、附编译好的库、vtk测试源码&#xff09; 教程描述 本…

2024.5.6

Widget::Widget(QWidget *parent): QWidget(parent) {//窗口相关设置this->setFixedSize(540,720);//背景颜色this->setStyleSheet("background-color:white");//去掉头部this->setWindowFlag(Qt::FramelessWindowHint);//标签相关设置QLabel *lab1 new QL…

嵌入式5-6QT

1> 思维导图 2> 自由发挥应用场景&#xff0c;实现登录界面。 要求&#xff1a;尽量每行代码都有注释。 #include "mywidget.h"MyWidget::MyWidget(QWidget *parent): QWidget(parent) {//设置标题this->setWindowTitle("MYQQ");//设置图标this…

底层逻辑(5)世界法则

底层逻辑(5)世界法则 世界三大法则 人是群居动物&#xff0c;所以每个人都避免不了和其他人打交道&#xff0c;特别是在大城市里&#xff0c;我们需要经常和陌生人打交道。 打交道的次数越多&#xff0c;你可能越能遇到一些所谓的巨婴或者杠精。这类人很难打交道&#xff0c…

从ChatGPT革命性的对话系统,看人机交互模式6个阶段的演变

ChatGPT引领革命&#xff0c;看人机交互六步飞跃 ©作者|wy 来源|神州问学 引言 在科技的浪潮中&#xff0c;人机交互模式不断演进&#xff0c;从最初的简单指令输入到如今的智能对话系统&#xff0c;每一次革新都昭示着人类与机器交流方式的深刻变革。ChatGPT&#xff0…

昂科烧录器支持O2Micro凹凸科技的电池组管理IC OZ7708

芯片烧录行业领导者-昂科技术近日发布最新的烧录软件更新及新增支持的芯片型号列表&#xff0c;其中O2Micro凹凸科技的电池组管理IC OZ7708已经被昂科的通用烧录平台AP8000所支持。 OZ7708是一款高度集成、低成本的电池组管理IC&#xff0c;适用于5~8s Li-Ion/Polymer电池组&a…

AVL树浅谈

前言 大家好&#xff0c;我是jiantaoyab&#xff0c;本篇文章给大家介绍AVL树。 基本概念 AVL树&#xff08;Adelson-Velsky和Landis树&#xff09;是一种自平衡的二叉搜索树&#xff0c;得名于其发明者G. M. Adelson-Velsky和E. M. Landis。在AVL树中&#xff0c;任何节点的…

OpenCV 入门(七)—— 身份证识别

OpenCV 入门系列&#xff1a; OpenCV 入门&#xff08;一&#xff09;—— OpenCV 基础 OpenCV 入门&#xff08;二&#xff09;—— 车牌定位 OpenCV 入门&#xff08;三&#xff09;—— 车牌筛选 OpenCV 入门&#xff08;四&#xff09;—— 车牌号识别 OpenCV 入门&#xf…

四川景源畅信:抖音个人开通橱窗操作流程介绍详情

随着短视频平台的快速发展&#xff0c;抖音已经成为越来越多人展示自我、分享生活的舞台。而其中&#xff0c;个人橱窗功能则为内容创作者提供了一个展示和销售商品的窗口。如果你是一位想要在抖音上开通个人橱窗的创作者或商家&#xff0c;了解详细的操作流程是迈向成功的第一…

如何通过前端表格控件在10分钟内完成一张分组报表?

前言&#xff1a; 当今时代&#xff0c;报表作为信息化系统的重要组成部分&#xff0c;在日常的使用中发挥着关键作用。借助报表工具使得数据录入、分析和传递的过程被数字化和智能化&#xff0c;大大提高了数据的准确性及利用的高效性。而在此过程中&#xff0c;信息化系统能…

无经验计科应届生前端面试遇到的问题整理

js数据类型有几种&#xff0c;分别是 原始数据类型&#xff08;Primitive data types&#xff09;: 字符串&#xff08;String&#xff09;: 用于表示文本数据&#xff0c;使用单引号&#xff08;‘’&#xff09;或双引号&#xff08;“”&#xff09;括起来。 数字&#xff…

AArch64 内存管理

本文是对arm developer网站《Learn the architecture - AArch64 memory management Guide》的学习笔记&#xff08;Documentation – Arm Developer&#xff09; 一、背景概述 本文介绍了AArch64中的内存转换&#xff0c;这是内存管理的关键&#xff0c;它解释了虚拟地址如何转…

第3章 WebServer重构

3.1 重构原生Web服务框架 3.1.1 分析原生Web服务框架 在服务端代码的 ClientHandler 中&#xff0c;请求解析、处理请求、返回响应的代码混杂在一起&#xff0c;这样的设计会导致代码难以维护和理解。为了提高代码的可读性、可维护性和可扩展性&#xff0c;我们需要对这些代码…

ComfyUI搭建和注意事项for WIN[笔记]

下载ComfyUI(GitHub - comfyanonymous/ComfyUI: The most powerful and modular stable diffusion GUI, api and backend with a graph/nodes interface.) 从源码上搭建比较麻烦&#xff0c;一般不推荐&#xff0c;所以跑到release里面找一个下载。我的显卡是GeFore GTX 1050 …

飞腾E2000运行Zephyr操作系统

Phytium-Zephyr-SDK 1. 仓库介绍 1.1 本仓库特色 此项目是一个开源软件&#xff0c;专为物联网领域设计&#xff0c;基于Zephyr实时操作系统&#xff0c;针对Phytium系列CPU进行了专门的适配和应用开发。我们的目标是降低开发者的使用门槛&#xff0c;提供了部署文档和使用指…

同向双指针(滑动窗口)算法

209. 长度最小的子数组 这里的更新结果就题来定 class Solution {public int minSubArrayLen(int target, int[] nums) {int sum 0;int len 0;int f 0;for(int left 0, right 0; right < nums.length;){//求和sum nums[right];while(sum > target){//lenint t ri…

MLP实现fashion_mnist数据集分类(1)-模型构建、训练、保存与加载(tensorflow)

1、查看tensorflow版本 import tensorflow as tfprint(Tensorflow Version:{}.format(tf.__version__)) print(tf.config.list_physical_devices())2、fashion_mnist数据集下载与展示 (train_image,train_label),(test_image,test_label) tf.keras.datasets.fashion_mnist.l…

张大哥笔记:卖盗版网课,获利 100 万被抓

这几天刷视频&#xff0c;看到一个新闻&#xff0c;某大学生卖盗版网课&#xff0c;把别人2000多正版网课&#xff0c;以做活动名义售卖20元&#xff0c;获利100多万被抓。 下方图片来自&#xff1a;极目新闻 卖这种盗版网课&#xff0c;门槛低&#xff0c;成本低&#xff0c;…

解决3D模型只显示线框材质的方法---模大狮模型网

在3D建模和渲染过程中&#xff0c;正确的材质和纹理是呈现逼真效果的关键。然而&#xff0c;有时候用户可能会遇到一个常见问题&#xff0c;即3D模型在渲染或查看时只显示线框材质&#xff0c;而没有正确的表面纹理和颜色。本文将介绍解决这一问题的几种方法&#xff0c;帮助用…

7 人赚 960 亿美元,数字天才的首次独舞

巴菲特股东大会 一年一度的巴菲特股东大会如常召开&#xff0c;只不过这次坐在老爷子左手边的不再是老搭档查理芒格&#xff0c;而是钦点的未来继任者&#xff0c;格雷格阿贝尔。 随着芒格&#xff08;99岁&#xff09;的离开&#xff0c;巴菲特&#xff08;93岁&#xff09;也…