首页 > 其他分享 >C语言:指针的进阶

C语言:指针的进阶

时间:2024-07-29 18:24:43浏览次数:8  
标签:进阶 zd void C语言 数组 printf sizeof 指针

指针的进阶

一、字符指针

(一)字符指针

字符指针指向的是字符串的首元素地址。

(二)常量字符串和字符数组

常量字符串不可以被修改并且在内存中(只读数据区)只会存在一份,而字符数组可以被修改。
在这里插入图片描述

二、指针数组和数组指针

(一)指针数组 int *p1[10]

指针数组是存放指针的数组。
代码中,arr数组就是指针数组。
使用指针数组,传参打印时使用二级指针接收。
在这里插入图片描述

(二)数组指针 int (*p2)[10]

数组指针是存放数组地址的指针 &arr
二位数组的数组名是第一行元素的地址
传参打印时使用数组指针接收。
在这里插入图片描述

三、函数指针

(一)函数指针

1、概念

指向函数的指针,记得要给指针加上()否则指针变量会和后面的函数调用操作符相结合,编译错误。
在这里插入图片描述

2、两段有趣的代码

(1)( * ( void(*)()0) )();

本质上是调用了0地址处的那个函数。
在这里插入图片描述

(2)void (signal(int, void ()(int)))(int);

在这里插入图片描述

(二)函数指针数组

存放函数指针的数组叫函数叫做函数指针数组。

void test(const char* str)
{
 printf("%s\n", str);
}
int main()
{
 //函数指针pfun
 void (*pfun)(const char*) = test;
 //函数指针的数组pfunArr
 void (*pfunArr[5])(const char* str);
 pfunArr[0] = test;
 //指向函数指针数组pfunArr的指针ppfunArr
 void (*(*ppfunArr)[5])(const char*) = &pfunArr;
 return 0;
}

转移表

利用函数指针数组,我们可以将switch语句改成转移表,这样的代码往往是比较简洁的。
在这里插入图片描述

(三)指向函数指针数组的指针

四、回调函数

(一)定义

当把一个函数的地址作为参数传递给另外一个函数,另一个函数用函数指针类型来接收,被调用的函数就是回调函数。
利用回调函数,我们往往可以简化代码,达到泛型编程。
在这里插入图片描述

(二)qsort函数

void qsort (void* base, size_t num, size_t size,
 int (*compar)(const void*,const void*));

这里我们使用了回调函数,只需要按需求写一个比较方式,qsort将会可以给任何类型的数据进行排序。

struct stu
{
	char name[20];
	int age;
};
int cmp_stu_by_name(const void* p1, const void* p2)
{
	return strcmp(((struct stu*)p1)->name,
	 ((struct stu*)p2)->name);
	 //记得要强制类型转化,指针才会按照字节数进行访问对应地址
}

(三)qsort自定义实现

在这里插入图片描述

五、sizeof 和 strlen 的剖析

(一)概念

sizeof :是操作符,统计的是字节数量,包括字符串末尾的’\0’。
strlen:字符串函数,遇到’\0’结束,统计字符串长度,如果没有’\0’,结果是随机值。
在这里插入图片描述

在这里插入图片描述

(二)sizeof例题

8/4 表示在32位平台是4个字节,64位平台是8个字节。
int main()
{
	int a[] = { 1,2,3,4 };
	printf("%zd\n", sizeof(a));//        16
	printf("%zd\n", sizeof(a + 0));//    8/4
	printf("%zd\n", sizeof(*a));//       4
	printf("%zd\n", sizeof(a + 1));//    8/4
	printf("%zd\n", sizeof(a[1]));//     4
	printf("%zd\n", sizeof(&a));//       8/4
	printf("%zd\n", sizeof(*&a));//      16
	printf("%zd\n", sizeof(&a + 1));//   8/4
	printf("%zd\n", sizeof(&a[0]));//    8/4
	printf("%zd\n", sizeof(&a[0] + 1));//8/4


	char* p = "abcdef";
	printf("%zd\n", sizeof(p));//p是指针变量。计算的是指针变量p的大小,4/8个字节
	printf("%zd\n", sizeof(&p));//&p是指针变量p的地址,4/8个字节	
	//&p -- char** -- 二级指针
	return 0;
}

(三)strlen例题

int main()
{
	char arr[] = { 'a','b','c','d','e','f' };
	printf("%zd\n", strlen(arr));//随机值
	printf("%zd\n", strlen(arr + 0));//随机值
	//printf("%zd\n", strlen(*arr));//arr是数组名表示首元素的地址
	//*arr 是首元素 -- 'a' - 97 ,传递给strlen后,strlen 会认为97就是地址,然后去访问内存,err
	//printf("%zd\n", strlen(arr[1]));//'b' -98 //err
	printf("%zd\n", strlen((char*) & arr));//随机值
	printf("%zd\n", strlen((char*) & arr + 1));//随机值
	printf("%zd\n", strlen(&arr[0] + 1));//随机值
	return 0;
}

六、指针杂论

(一)指针大小

指针的大小只和环境有关系。在32位平台下是4个字节,64位平台下是8个字节。

(二)指针类型的作用

不同的指针类型在指针的加减,*(解引用),和访问权限上面有差异

1、指针的加减

我们发现指针相加减的规则是
(类型)*p = a;
p + n = p + n * (sizeof(类型))
在这里插入图片描述

在这里插入图片描述

2、解引用和访问权限

这里要将int类型的地址转换成char*操作,需要进行强制类型转换。
在这里插入图片描述

下面这串代码看似正确,实际上,char*指针的访问权限只有一个字节,所以如果数组中值变大,就会发生错误。
在这里插入图片描述

3、强大的void指针

void指针相当于万能指针,可以将任何类型的变量赋值给它,但是之后指针变量不可以再重新赋值或者直接相加减。
在这里插入图片描述

(三)const修饰指针

const放在后面,指针指向区域不能改动,而放在前面,指针的内容不可修改。
在这里插入图片描述

(四)数组名的理解

一维数组:数组名其实是数组的首元素地址。
二维数组:数组名是第一排元素的地址。
但是有两种情况除外。
1、sizeof(数组名) 代表的是整个数组的大小。
2、&(数组名)代表整个数组的地址。
在这里插入图片描述

八、结束语

相信通过这篇文章,能对指针有更深刻的理解,对指针的应用也有提升。这是小编所希望看到的。大家如果也觉得有帮助,那就动动小手支持下吧!
在这里插入图片描述

标签:进阶,zd,void,C语言,数组,printf,sizeof,指针
From: https://blog.csdn.net/2301_81454749/article/details/140740418

相关文章

  • C语言:运算符优先级
    由上到下,优先级依次递减运算符结合性()[] -> .从左至右!~++---(type)*&sizeof从右至左*/%从左至右+-从左至右<<>>从左至右<<=>>=从左至右==!=从左至右&从左至右^从左至右|从左至右&&从左至右||从左至右?:从右至左assignments从右至左,从左至右......
  • MySQL 学习笔记 进阶(SQL优化,视图,存储过程 上)
    SQL优化 SQL优化-插入数据insert优化·批量插入insertintotb_uservalues(1,'Tom'),(2,'Cat'),(3,'Jerry');·手动提交事务starttransaction;insertintotb_uservalues(1,'Tom'),(2,'Cat'),(3,'Jerry......
  • c语言·其二
    1.代码区:可读可执行2.堆栈:(参数,局部变量,临时数据)3.堆:(动态申请,大小可变)可读可写5.常量区:只读变量变量的声明全局变量inta,b,c;//全局变量的声明  voidFun()  {   a=10;//全局变量的赋值   b=20;   c=a;  }局部变量voidFun()  { ......
  • C语言基础算法
    C语言基础算法目录C语言基础算法1、阶乘递归实现循环实现2、排序冒泡排序选择排序3、斐波那契数列4、ASCII码的使用1、阶乘递归实现#include<stdio.h>//递归函数计算阶乘intfactorial(intn){if(n==0||n==1)return1;elsereturnn......
  • 【K8s】专题七(4):Kubernetes 服务发现之 Ingress 进阶
    以下内容均来自个人笔记并重新梳理,如有错误欢迎指正!如果对您有帮助,烦请点赞、关注、转发!欢迎扫码关注个人公众号!目录一、官方文档二、Ingress进阶使用(示例)1、Ingress实现重定向2、Ingress实现路由跳转3、Ingress实现自定义配置4、Ingress实现CORS5、Ingress实......
  • C语言中的函数(保姆级详细讲解)
    文章目录一.函数的概念1.1库函数1.2自定义函数二.函数的参数1.实参2.形参3.形参和实参的关系(传值调用)4.数组做函数参数(传址调用)三.函数的return语句四.函数的嵌套调用和链式访问1.嵌套调用2.链式访问五.static和extern1.作用域和生命周期2.static2.1s......
  • 从零开始学嵌入式技术之C语言04:进制与转换
    一:进制        计算机世界中只有二进制,所以计算机中存储和运算的所有数据都要转为二进制。包括数字、字符、图片、声音、视频等。(1)二进制:0、1,满2进1。(2)十进制:0-9,满10进1。(3)十六进制:0-9及A-F,满16进1。十六进制中,除了0到9十个数字外,还引入了字母,以便表示超过......
  • 从零开始学嵌入式技术之C语言01:环境的搭建
    一:计算机语言简史(1)机器语言        1946年2月14日,世界上第一台计算机ENIAC诞生,使用的是最原始的穿孔卡片。这种卡片上使用的是用二进制代码表示的语言,与人类语言差别极大,这种语言就称为机器语言。(2)汇编语言        使用英文缩写的助记符来表示基本的操作,这......
  • 《重生到现代之从零开始的C语言生活》—— 数组
    数组数组是个啥数组是一组相同类型元素的集合数组分为一维数组和多维数组,多维数组比较常见的是二维数组一维数组的创建和初始化一维数组的建立的基本语法typearr_name[常量]存放的数组的值被称为数组的元素,在创建时可以指定数组的大小和数组的元素类型比如想创建......
  • 嵌入式初学-C语言-五
    C语言语句概述C语句的分类⑴控制语句 用于完成一定的控制功能    ①if(  )……else……    ②for(  )……    ③while(  )……    ④do……while(  )    ⑤continue    ⑥break    ⑦switch( ......