C语言学习笔记---指针进阶01

C语言程序设计笔记---016

  • C语言指针进阶前篇
    • 1、字符指针
    • 2、指针数组
      • 2.1、指针数组例程1 -- 模拟一个二维数组
      • 2.2、指针数组例程2
    • 3、数组指针
      • 3.1、回顾数组名?
      • 3.2、数组指针定义与初始化(格式)
      • 3.3、数组指针的作用 --- 常用于二维数组
      • 3.4、数组指针 --- 二维数组的应用
    • 4、数组的参数探究 --- 指针参数作为参数
      • 4.1、一维数组传参
      • 4.2、二维数组传参
      • 4.3、指针传参
    • 5、函数指针
      • 5.1、函数指针初始化(格式)
    • 6、巩固知识点
      • 6.1、解释以下代码1
      • 6.2、解释以下代码2
    • 7、结语

C语言指针进阶前篇

前言:
什么是指针?
指针是编程语言中的一个对象,利用地址,它的值直接指向存在电脑存储器中另一个地方的值。
由于通过地址能找到所需的变量单元,可以说,地址指向该变量单元。因此,将地址形象化的称为“指针”
即:能通过它能找到以它为地址的内存单元
另外,平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量。

/知识点汇总/

1.指针变量就是变量,用来存放地址,地址唯一标识一块内存空间
2.指针的大小,是固定的4/8个字节(32位/64位)、
3.指针是有类型的,指针的类型决定了指针±整数的步长,以及指针解引用的权限、
4.指针的运算(指针加减整数:偏移量;指针减指针:是指针和指针之间的元素个数;指针关系运算:指针大小比较)
详见:指针初阶

1、字符指针

指针就是地址,口语中说的指针指的是指针变量
整型指针:指向整型数据的指针
字符指针:就是指向字符型数据的指针变量

#include <stdio.h>
int main()
{char ch = 'w';char* pc = &ch;char* p = "abcdef";//这里的字符串等价于表达式,然后返回的结果是第一个字符的地址(可理解为数组)//注意的是,这里的“abcdef”属于常量表达式,不可改变printf("%c\n","abcdef"[3]);//d//类似于数组名 --- “abcdef” ,所以可理解为数组形式const* pd = "abccdef";printf("%s\n", pd);//abcdefprintf("%c\n", *pd);//areturn 0;
}

注意的是
(1)、这里的字符串等价于表达式,然后返回的结果是第一个字符的地址(可理解为数组)
(2)、这里的“abcdef”属于常量表达式,不可改变

例题

#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("1 to 2 same\n");}else{printf("1 to 2 not same\n");}if (str3 == str4){printf("3 to 4 same\n");}else{printf("3 to 4 not same\n");}if (&str3 == &str4){printf("&3 to &4 same\n");}else{printf("&3 to &4 not same\n");}return 0;
}

小结
(1)、str1 与 str2 是两个不同的空间地址所以,不相等
(2)、str3 与 str4 由于保存的是同一个常量表达式,所以它们指向的地址相同,则得到的值相同;但是str3 和str4 本身的地址是不同的

2、指针数组

字符数组 – 存放字符的数组
整型数组 – 存放整型的数组
指针数组 – 存放指针的数组,存放在数组中的元素是指针类型

如:
int* arr[5];
char* ch[6];

2.1、指针数组例程1 – 模拟一个二维数组

#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* int* int*//指针数组int* arr[] = {arr1,arr2,arr3};int i = 0;for (i = 0; i < 3; i++){int j = 0;for (j = 0; j < 5; j++){printf("%d ",arr[i][j]);}printf("\n");}return 0;
}

2.2、指针数组例程2

#include <stdio.h>
int main()
{//指针数组char* arr[5] = {"hello bit","hehe","abcf","cojag","waofrdf"};int i = 0;for (i = 0; i < 5; i++){printf("%s\n",arr[i]);}return 0;
}

3、数组指针

指针数组 ---- 是数组,是存放指针的数组
数组指针 — 是指针
字符指针 — 是指向字符的指针
整型指针 – 指向整型的指针
浮点型指针 – 指向浮点数的指针

3.1、回顾数组名?

数组名是数组首元素的地址,但是存在两个例外,sizeof(数组名),&数组名;
两个例外的数组名,表达的是,整个数组的地址

数组指针 — &arr
虽然与首元素地址值相同,但进行指针运算时±,发现,加减的整个数组的大小字节
同时指针类型决定了,指针+1,到底+几个字节(步长)

#include <stdio.h>
int main()
{int arr[10];printf("%p\n",arr);printf("%p\n",arr+1);printf("%p\n", &arr);printf("%p\n", &arr + 1);printf("%p\n", arr[0]);printf("%p\n", arr[0] + 1);printf("%p\n", &arr[0]);printf("%p\n", &arr[0] + 1);return 0;
}

3.2、数组指针定义与初始化(格式)

#include <stdio.h>
int main()
{int arr[10] = { 0 };//int* p = &arr;int(*p)[10] = &arr;//p是用来存放数组的地址的,p就是数组指针char* arr2[5];char* (*pc)[5] = &arr2;//(*pc)说明pc是一个指针类型,(*pc)[5],表示数组指针,char* 表示该数组类型属于字符指针类型//int arr3[] = { 1,2,3 };//int(*p3)[] = &arr3;//数组指针的[]操作符的参数必须指明,否则报错return 0;
}

3.3、数组指针的作用 — 常用于二维数组

#include <stdio.h>
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };//数组指针int(*p)[10] = &arr;int i = 0;for(i=0;i<10;i++){printf("%d ",(*p)[i]);}//指针变量int* p = &arr;int i = 0;for (i = 0; i < 10; i++){printf("%d ", p[i]);}return 0;
}

3.4、数组指针 — 二维数组的应用

二维数组的数组名是首元素的地址,即:数组指针的首元素地址是,第一行的地址

#include <stdio.h>
//二维数组传参也是二维数组的形式
//void print(int arr[3][5], int row, int col)//形参是数组形式
//{
//	int i = 0;
//	for (i = 0; i < 3; i++)
//	{
//		int j = 0;
//		for (j = 0; j < 5; j++)
//		{
//			printf("%d ",arr[i][j]);
//		}
//		printf("\n");
//	}
//}
void print(int (*p)[5], int row, int col)//形参是指针形式,指向第一行
{int i = 0;for (i = 0; i < 3; i++){int j = 0;for (j = 0; j < 5; j++){printf("%d ",p[i][j]);}printf("\n");}
}
int main()
{int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{6,7,8,9,10} };print(arr,3,5);//二维数组传参,行,列return 0;
}

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);return 0;
}

4.2、二维数组传参

#include <stdio.h>void test(int arr[3][5])//ok
{}
void test(int arr[][])//No,列不可以省
{}
void test(int arr[][5])//ok
{}
void test(int *arr)//No,不能以一维数组接收二维数组,因为二维数组的首元素地址是第一行的地址,而不是第一个元素的地址
{}
void test(int* arr[5])//No,类型不同,int* 与int
{}
void test(int (*arr)[5])//ok,数组指针,指向第一行
{}
void test(int **arr)//No,二级指针用于指向一级指针的地址
{}int main()
{int arr[3][5];test(arr);return 0;
}

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,10 };int* p = arr;int sz = sizeof(arr) / sizeof(arr[0]);//一级指针p传给函数,作形参print(p,sz);return 0;
}

思考扩展1
当我们遇见一个函数的形参是一级指针的时候,考虑函数的实参可以传什么?
答:只要是可以传递的对应类型的地址/一级指针变量就可以,以及数组名也行。

二级指针传参
二级指针传参时,形参写成二级指针形式

#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);//test(&p);等价return 0;
}

思考扩展2
当我们遇见一个函数的形参是一级指针的时候,考虑函数的实参可以传什么?
答:只要是可以传递的对应类型的一级指针地址/二级指针变量就可以,一级指针类型的数组名也行。

5、函数指针

数组指针 – 指向数组的指针 – 存放的是数组的地址 — &数组名就是整个数组的地址
函数指针 – 指向函数的指针 — 存放的是函数的地址

如何取得函数的地址呢?也是通过 &函数名吗?
答:&操作符加函数名即可

5.1、函数指针初始化(格式)

#include <stdio.h>int Add(int x, int y)
{return (x + y);
}int main()
{//&函数名就是函数的地址//函数名也是函数的地址printf("%p\n", &Add);printf("%p\n", Add);//均表示函数的地址//函数指针//int (*pf1)(int , int) = Add;//pf1就是函数指针变量int (*pf2)(int, int) = &Add;//pf2同样是函数指针变量int ret = (*pf2)(2, 3);//因为Add与&Add等价//常规写法://int ret = Add(2,3);//所以*号就可以省略//int ret = pf2(2,3)printf("%d\n",ret);
}

6、巩固知识点

6.1、解释以下代码1

int arr[5];//arr是一个存放5个整型数据的数组
int* parr1[10];//parr1是一个数组,数组的10个元素类型是int*
int(*parr2)[10];//parr2是一个数组指针,该指针指向的数组,指向数组的10个元素类型是int
int(*parr3[10])[5];//parr3是一个数组,是存放数组指针的10元素的数组,存放的这个数组指针,指针指向的5个元素是int类型

6.2、解释以下代码2

#include <stdio.h>
int main()
{(*(void(*)())0)();//整体是一个函数调用//(void(*)()函数指针类型//(void(*)()) 强制类型转换为函数指针类型//(*(类型)0)(); --- 所以这段代码表示://调用0地址处的函数,这个函数没有参数,且返回值类型为void省略不写void (*signal(int, void(*)(int)))(int);//整体是一个函数声明//void(*)(int)函数指针作为参数//signal(int, void(*)(int)) --- 函数,一个参数是int类型,一个参数是函数指针类型,返回值类型也是作为函数指针类型//(*signal(int, void(*)(int))) --- 函数指针//(*signal(int, void(*)(int)))(int) --- 函数指针参数是一个int类型参数//void (*signal(int, void(*)(int)))(int) -- 一个返回值类型为空,参数是一个整型的函数指针的声明//所以这段代码表示://是一个函数声明,声明的是signal函数,signal函数的参数有两个,一个是int类型,一个是函数指针类型,该类型是void(*)(int),该函数指针指向的函数,参数类型是int类型,返回值类型为void//signal函数的返回值类型也是函数指针类型,该类型是void (*)(int),该函数指针指向的函数,参数类型是int类型,返回值类型为void//利用typedef 对这段代码简化:typedef void(*pfun_t)(int);//typedef 对函数指针类型重命名时,被重名的变量名,放在*面,即pfun_t的位置pfun_t signal(int, pfun_t);return 0;
}

7、结语

C语言指针进阶前篇到此结束啦!
未完待续…
半亩方糖一鉴开,天光云影共徘徊。
问渠哪得清如许?为有源头活水来。–朱熹(观书有感)

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

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

相关文章

Vue中使用element-plus中的el-dialog定义弹窗-内部样式修改-v-model实现-demo

效果图 实现代码 <template><el-dialog class"no-code-dialog" v-model"isShow" title"没有收到验证码&#xff1f;"><div class"nocode-body"><div class"tips">请尝试一下操作</div><d…

智能化巡护通信解决方案全天候保障油气管线

油气管道在我国油气资源运输过程中发挥着“大动脉"的角色&#xff0c;维护油气管道运输安全与国家能源安全、公共安全之间有着密不可分的联系。从这一角度来看&#xff0c;落实油气管道巡查保护工作的现实价值&#xff0c;在当前的实践中&#xff0c;无线通信解决方案需要…

C语言易错点整理

前言&#xff1a; 本文涵盖了博主在平常写C语言题目时经常犯的一些错误&#xff0c;在这里帮大家整理出来&#xff0c;一些易错点会帮大家标识出来&#xff0c;希望大家看完这篇文章后有所得&#xff0c;引以为戒~ 一、 题目&#xff1a; 解答&#xff1a; 首先在这个程序中…

Unity ProBuilder SetUVs 不起作用

ProBuilder SetUVs 不起作用 &#x1f41f; 需要设置face.manulUV true public static void Set01UV(this ProBuilderMesh mesh){foreach (var face in mesh.faces){face.manualUV true;//设置为手动uv}var vertices mesh.GetVertices().Select(v > v.position).ToArray(…

mq与mqtt的关系

文章目录 mqtt 与 mq的区别mqtt 与 mq的详细区别传统消息队列RocketMQ和微消息队列MQTT对比&#xff1a;MQ与RPC的区别 mqtt 与 mq的区别 mqtt&#xff1a;一种通信协议&#xff0c;规范 MQ&#xff1a;一种通信通道&#xff08;方式&#xff09;&#xff0c;也叫消息队列 MQ…

openCV实战-系列教程5:边缘检测(Canny边缘检测/高斯滤波器/Sobel算子/非极大值抑制/线性插值法/梯度方向/双阈值检测 )、原理解析、源码解读

打印一个图片可以做出一个函数&#xff1a; def cv_show(img,name):cv2.imshow(name,img)cv2.waitKey()cv2.destroyAllWindows() 1、Canny边缘检测流程 Canny是一个科学家在1986年写了一篇论文&#xff0c;所以用自己的名字来命名这个检测算法&#xff0c;Canny边缘检测算法…

微信小程序开发教学系列(3)- 页面设计与布局

3. 页面设计与布局 在微信小程序开发中&#xff0c;页面的设计和布局是非常重要的。一个好的页面设计可以提升用户体验&#xff0c;并使小程序更加吸引人。本章节将介绍如何设计和布局微信小程序的页面。 3.1 页面结构和样式的创建和设置 在创建微信小程序页面时&#xff0c…

C#-Tolewer和ToUpper的使用

目录 简介: 好处:​ 过程: 总结&#xff1a; 简介: 字符串是不可变的&#xff0c;所以这些函数都不会直接改变字符串的内容&#xff0c;而是把修改后的字符串的值通过函数返回值的形式返回。 ToLower和ToUpper是字符串处理函数&#xff0c;用于将字符中的英文字母转换为小…

使用DPO微调Llama2

简介 基于人类反馈的强化学习 (Reinforcement Learning from Human Feedback&#xff0c;RLHF) 事实上已成为 GPT-4 或 Claude 等 LLM 训练的最后一步&#xff0c;它可以确保语言模型的输出符合人类在闲聊或安全性等方面的期望。然而&#xff0c;它也给 NLP 引入了一些 RL 相关…

linux篇---使用systemctl start xxx启动自己的程序|开机启动|守护进程

linux篇---使用systemctl start xxx启动自己的程序|开机启动|守护进程 1、创建服务2、修改权限3、启动服务4、测试 机器&#xff1a;Nvidia Jetson Xavier系统&#xff1a;ubuntu 18.04 最近在使用symfony的console组件&#xff0c;需要执行一个后台的php进程&#xff0c;并且…

C++ Day5

目录 一、静态成员 1.1 概念 1.2 格式 1.3 银行账户实例 二、类的继承 2.1 目的 2.2 概念 2.3 格式 2.4 继承方式 2.5 继承中的特殊成员函数 2.5.1 构造函数 2.5.2析构函数 2.5.3 拷贝构造函数 2.5.4拷贝赋值函数 总结&#xff1a; 三、多继承 3.1 概念 3.2 格…

k8s--基本概念理解

必填字段 在要创建的 Kubernetes 对象的文件中.yaml&#xff0c;您需要设置以下字段的值&#xff1a; apiVersion- 您使用哪个版本的 Kubernetes API 创建此对象 kind- 你想创建什么样的对象 metadata- 有助于唯一标识对象的数据&#xff0c;包括name字符串、UID和可选namesp…

大数据领域都有什么发展方向

近年来越来越多的人选择大数据行业&#xff0c;大数据行业前景不错薪资待遇好&#xff0c;各大名企对于大数据人才需求不断上涨。 大数据从业领域很宽广&#xff0c;不管是科技领域还是食品产业&#xff0c;零售业等都是需要大数据人才进行大数据的处理&#xff0c;以提供更好…

Python调用文心一言的API

最近申请了文心一言的key&#xff0c;然后尝试调用了一下文心一言&#xff0c;这里使用一个简单的方式来调用文心一言&#xff1a; pip install paddle-pipelinesfrom pipelines.nodes import ErnieBotapi_key "your apply key" secret_key "your apply secr…

【python】Leetcode(primer-set)

文章目录 78. 子集&#xff08;集合的所有子集&#xff09;90. 子集 II&#xff08;集合的所有子集&#xff09;792. 匹配子序列的单词数&#xff08;判断是否为子集&#xff09;500. 键盘行&#xff08;集合的交集&#xff09;409. 最长回文串&#xff08;set&#xff09; 更多…

测试先行:探索测试驱动开发的深层价值

引言 在软件开发的世界中,如何确保代码的质量和可维护性始终是一个核心议题。测试驱动开发(TDD)为此提供了一个答案。与传统的开发方法相比,TDD鼓励开发者从用户的角度出发,先定义期望的结果,再进行实际的开发。这种方法不仅可以确保代码满足预期的需求,还可以在整个开…

IBM Db2 笔记

目录 1. IBM Db2 笔记1.1. 常用命令1.2. 登录命令行模式 (Using the Db2 command line processor)1.3. issue1.3.1. db2: command not found/SQL10007N Message "-1390" could not be retreived. Reason code: "3".1.3.2. db2 修改 dbm cfg 的时候报 SQL50…

C++ Day4

目录 一、拷贝赋值函数 1.1 作用 1.2 格式 二、匿名对象 2.2 格式 三、友元 3.1作用 3.2格式 3.3 种类 3.4 全局函数做友元 3.5类做友元 3.6 成员函数做友元 3.7注意 四、常成员函数和常对象 4.1 常成员函数 4.1.1格式 示例&#xff1a; 4.2 常对象 作用&…

shell学习笔记(详细整理)

主要介绍&#xff1a;主要是常用变量&#xff0c;运算符&#xff0c;条件判断&#xff0c;流程控制&#xff0c;函数&#xff0c;常用shell工具(cut,sed,awk,sort)。 一. Shell概述 程序员为什么要学习Shell呢&#xff1f; 1&#xff09;需要看懂运维人员编写的Shell程序。 2…

恒运资本:什么是股票分红和基金分红?两者有什么区别?

出资者在进行股票出资和基金出资的时分&#xff0c;能够参与股票分红或许基金分红&#xff0c;可是许多新手对分红不是很了解。那么什么是股票分红和基金分红&#xff1f;两者有什么区别&#xff1f;下面就由恒运资本为大家分析&#xff1a; 什么是股票分红和基金分红&#xff…