首页 > 其他分享 >C语言(七)----指针(下)

C语言(七)----指针(下)

时间:2024-11-26 22:32:17浏览次数:9  
标签:arr int C语言 ---- zd 地址 printf sizeof 指针

深入理解指针(4)

字符指针变量

#include<stdio.h>
int main()
{
	char ch = 'h';
	char* pch = &ch;
	printf("%c\n",*pch);

	*pch = 'g';
	printf("%c\n",*pch);
	return 0;
}
//结果为:
//h
//g

//也可以:
#include<stdio.h>
int main()
{
	char* pch = 'h';
	printf("%c\n",pch);

	pch = 'g';
	printf("%c\n",pch);
	return 0;
} 
//结果为:
//h
//g

数组指针变量

类比:

字符指针变量:char*:存放字符变量的地址—>指向字符变量的指针

整型指针变量:int*:存放整型变量的地址—>指向整型变量的指针

数组指针变量:存放数组的地址—>指向数组的指针

int arr[5] = {0};
int (*p)[5] = &arr;//数组的地址
//*说明p是指针变量,并非解引用              
//p就是能够存放数组地址的一种指针变量--->数组指针变量

二维数组传参的本质

函数指针变量

函数指针是指向函数的,存放的是函数的地址

函数名是函数的地址,&函数名也是函数的地址,没有区别

int Add(int x,int y)
{
 return x + y;   
}
int main()
{
    int a = 10;
    int b = 20;
    int (*pf)(int ,int) = &Add;
    //pf就是函数指针变量
    //一样;int (* pf)(int a,int b) = &Add;
    //pf == Add,*说明pf是指针变量
    return 0;
}
typedef关键字
unsigned int num;
typedef unsigned int uint;
int main()
{
    unsigned int num;
    uint num2;
    return 0;
}

函数指针数组

转移表

简易计算器
#include<stdio.h>
void menu()
{
	printf("------------------------\n");
	printf("------1,Add   2,Sub------\n");
	printf("------3,Mul   4,Div------\n");
	printf("---------0,exit---------\n");
	printf("------------------------\n");

}
int Add(int x, int y)
{
	return x + y;
}
int Sub(int x, int y)
{
	return x - y;
}
int Mul(int x, int y)
{
	return x * y;
}
int Div(int x, int y)
{
	return x / y;
}

int main()
{
	int input = 0;
	do
	{
		menu();
		printf("请选择:");
		scanf("%d",&input);
		int a = 0;
		int b = 0;
		int r = 0;

		switch (input)
		{
		case 1:
			printf("输入两个整数:");
			scanf("%d %d",&a,&b);
			r = Add(a, b);
			printf("a+b=%d\n",r);
			break;
		case 2:
			printf("输入两个整数:");
			scanf("%d %d", &a, &b);
			r = Sub(a, b);
			printf("a-b=%d\n", r);
			break;
		case 3:
			printf("输入两个整数:");
			scanf("%d %d", &a, &b);
			r = Mul(a, b);
			printf("a*b=%d\n", r);
			break;
		case 4:
			printf("输入两个整数:");
			scanf("%d %d", &a, &b);
			r = Div(a, b);
			printf("a/b=%d\n", r);
			break;
		case 0:
			printf("退出\n");
			break;
		default:
			break;
		}

	} while (input);

	return 0;
}
简易计算器的优化1

进行优化

仅需对主函数内部进行优化

int main()
{
	int input = 0;
	int (*pf_arr[])(int, int) = { 0,Add,Sub,Mul,Div };
	do
	{
		menu();
		printf("请选择:");
		scanf("%d", &input);
        
		int a = 0;
		int b = 0;
		int r = 0;
		if (input == 0)
		{
			printf("退出\n");
		}
		else if (input >= 1 && input <= 4)
		{
			scanf("%d %d",&a,&b);
			r = pf_arr[input](a,b);
			printf("%d\n",r);
		}
		else
		{
			printf("输入不合法,重新输入\n");
		}
	} while (input);

	return 0;
}

深入理解指针(5)

回调函数

回调函数就是一个通过函数指针调用的函数

简易计算器的优化2
void Calc(int (*pf)(int, int))
{
	int a = 0;
	int b = 0;
	int r = 0;
	printf("输入两个整数:");
	scanf("%d %d", &a, &b);
	r = pf(a, b);
	printf("%d\n",r);
}

int main()
{
	int input = 0;
	do
	{
		menu();
		printf("请选择:");
		scanf("%d",&input);
		
		switch (input)
		{
		case 1:
			Calc(Add);
			break;
		case 2:
			Calc(Sub);
			break;
		case 3:
			Calc(Mul);
			break;
		case 4:
			Calc(Div);
			break;
		case 0:
			printf("退出\n");
			break;
		default:
			break;
		}

	} while (input);

	return 0;
}

qsort使用示例

qsort排序整型数据
#include<stdio.h>
#include<string.h>

int cmp_arr_by_int(const void* e1, const void* e2)
{
	return (*(int*)e1 - *(int*)e2);
}

void Print_arr(int* arr,int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ",arr[i]);
	}
	printf("\n");
}
void test1()
{
	int arr[10] = { 1,5,3,2,8,6,0,9,7,4 };
	int sz = sizeof(arr) / sizeof(arr[0]);

	qsort(arr, sz, sizeof(arr[0]), cmp_arr_by_int);
	Print_arr(arr, sz);
}

int main()
{
	test1();
	return 0;
}
qsort排序结构体数据
#include<stdio.h>
#include<stdlib.h>//使用struct结构体要包含的头文件
#include<string.h>//使用strcmp比较字符串要包含的头文件

struct Stu
{
	char name[20];
	int age;
};

int cmp_arr_by_name(const void* e1, const void* e2)
{
    //比较两个字符串,前者大则返回>0的值,后者大则返回<0的值,相等返回0
    //*(struct Stu*)e1).name,将e1强制类型转换为struct Stu*后解引用
	return strcmp(((struct Stu*)e1)->name,((struct Stu*)e2)->name);
    
    //也可以写成
    //return strcmp((*(struct Stu*)e1).name,(*(struct Stu*)e2).name);
}

void Print_Stu(struct Stu* arr, size_t sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
        //打印排序好的字符串
		printf("%s " ,((arr[i]).name));
	}
	printf("\n");
}

void test()
{
	struct Stu arr[3] = { {"zhangsan",18}, {"lisi",35},{"wangwu",12} };
	int sz = sizeof(arr) / sizeof(arr[0]);
    //使用qsort函数按照名字顺序排序
	qsort(arr, sz, sizeof(arr[0]), cmp_arr_by_name);
	Print_Stu(arr, sz);//打印排序好的字符串
}

int main()
{
	test();
	return 0;
}

qsort函数的模拟实现

#include<stdio.h>

int cmp_int(const void* e1, const void* e2)
{
	return  (*(int*)e1 - *(int*)e2);
}

void Swap(void* e1,void* e2,int width)
{
	int i = 0;
	for (i = 0; i < width; i++)
	{
		char temp = *((char*) e1 + i);
		*((char*) e1 + i) = *((char*) e2 + i);
		*((char*) e2 + i) = temp;
	}
}

int My_sort(void* base, size_t sz, size_t width,int(*cmp)(const void* e1, const void* e2))
{
	int i = 0;
	for (i = 0; i < sz - 1; i++)
	{
		int j = 0;
		for (j = 0; j < sz - 1 - i; j++)
		{
			if (cmp((char*)base+j*width, (char*)base + (j+1) * width) > 0)
			{
				Swap((char*)base + j * width, (char*)base + (j + 1) * width,width);
			}
		}
	}
}

void Print_arr(int* arr, int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
}

void test()
{
	int arr[10] = { 1,5,3,2,8,6,0,9,7,4 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	
	My_sort(arr,sz, sizeof(arr[0]),cmp_int);
	Print_arr(arr,sz);
}


int main()
{
	test();
	return 0;
}

深入理解指针(6)

sizeofstrlen的对比

sizeof

是操作符,不关注内存中放的内容,只求所占内存空间的大小,单位是字节

strlen

是函数,求字符串长度统计的是\0之前字符的个数,直到查找到\0,可能存在越界访问

一维数组

#include<stdio.h>

int main()
{
	int a[] = { 1,2,3,4 };

	printf("%zd\n", sizeof(a));//16字节
	printf("%zd\n", sizeof(a + 0));//4/8
    //a作为数组名,并未单独放在sizeof内部,a就是数组首元素的地址
	//a+0还是数组首元素的地址,sizeof(a+0)计算的是一个地址的大小,那么就是4/8个字节
	printf("%zd\n", sizeof(*a));//4
    //a是数组首元素的地址,*a就是数组首元素,sizeof(*a)计算的是数组首元素大小,即4字节
	printf("%zd\n", sizeof(a + 1));//4/8
    //a就是数组首元素的地址,a+1就是第二个元素的地址,计算的是一个地址的大小,即4/8个字节
	printf("%zd\n", sizeof(a[1]));//4
    //sizeof(a[1])计算的是第二个元素的大小,即4字节
	printf("%zd\n", sizeof(&a));//4/8
    //&a取出的是整个数组的地址,是地址就是4/8字节
	printf("%zd\n", sizeof(*&a));//16
    //数组的地址解引用访问的是整个数组,大小是16字节
	printf("%zd\n", sizeof(&a + 1));//4/8
    //&a+1是数组的地址在跳过整个数组后的地址,是地址就是4/8字节
	printf("%zd\n", sizeof(&a[0]));//4/8
    //首元素地址,4/8字节
	printf("%zd\n", sizeof(&a[0] + 1));//4/8
    //第二个元素地址,4/8字节

	 return 0;
}
#include<stdio.h>

int main()
{
	char arr[] = {'a','b','c,','d','e','f'};

	printf("%zd\n",sizeof(arr));//6
	//计算整个数组的大小
	printf("%zd\n",sizeof(arr + 0));//4/8
	//计算数组首元素地址
	printf("%zd\n",sizeof(*arr));//1
	//计算数组首元素大小
	printf("%zd\n",sizeof(arr[1]));//1
	//第二个元素大小
	printf("%zd\n",sizeof(&arr));//4/8
	//&arr是整个数组地址,是地址就是4/8字节
	printf("%zd\n",sizeof(&arr + 1));//4/8
	//跳过整个数组后的地址,4/8
	printf("%zd\n",sizeof(&arr[0] + 1));//4/8
	//第二个元素地址,4/8

	return 0;
}

#include<stdio.h>
#include<string.h>

int main()
{
	char arr[] = { 'a','b','c,','d','e','f' };

	printf("%zd\n",strlen(arr));//没有\0随机值
	printf("%zd\n",strlen(arr + 0));//没有\0随机值
	//printf("%zd\n",strlen(*arr));//*arr是'a'ASSII值就是97,strlen会将97当做地址使用,这时就是非法访问
	//printf("%zd\n",strlen(arr[1]));//同上,非法访问
	printf("%zd\n",strlen(&arr));//没有\0随机值
	printf("%zd\n",strlen(&arr + 1));//没有\0随机值
	printf("%zd\n",strlen(&arr[0] + 1));//&arr[0] + 1得到第二个元素地址,没有\0,是随机值

	return 0;
}
#include<stdio.h>

int main()
{
	char arr[] = "abcdef";//字符串末尾隐藏着\0

	printf("%zd\n",sizeof(arr));//7
	printf("%zd\n",sizeof(arr + 0));//4/8
	printf("%zd\n",sizeof(*arr));//1
	printf("%zd\n",sizeof(arr[1]));//1
	printf("%zd\n",sizeof(&arr));//4/8
	printf("%zd\n",sizeof(&arr + 1));//4/8
	printf("%zd\n",sizeof(&arr[0] + 1));//4/8

	return 0;
}
#include<stdio.h>
#include<string.h>

int main()
{
	char arr[] = "abcdef";//字符串末尾隐藏着\0

	printf("%zd\n", strlen(arr));//6
	printf("%zd\n", strlen(arr + 0));//6
	//printf("%zd\n", strlen(*arr));//得到'a'ASCII值是97.访问97这个地址,是非法访问
	//printf("%zd\n", strlen(arr[1]));//得到'b'ASCII值是96.访问97这个地址,是非法访问
	printf("%zd\n", strlen(&arr));//6
	printf("%zd\n", strlen(&arr + 1));//跳过整个数组,\0位置不确定,随机值
	printf("%zd\n", strlen(&arr[0] + 1));//5

	return 0;
}

两种理解:

p[0]==*(p+0)

p[0],类似数组的下标访问==arr[0]

#include<stdio.h>
int main()
{
	char* p = "abcdef";//字符串末尾隐藏着\0

	printf("%zd\n",sizeof(p));//计算的是p这个指针变量的大小,4/8
	printf("%zd\n",sizeof(p + 1));//p+1是第二个字符的地址,4/8
	printf("%zd\n",sizeof(*p));//第一个字符a,是1
	printf("%zd\n",sizeof(p[0]));//第一个字符a,是1
	printf("%zd\n",sizeof(&p));//地址,4/8
	printf("%zd\n",sizeof(&p + 1));//是b的地址,4/8
	printf("%zd\n",sizeof(&p[0] + 1));//是b的地址,4/8

	return 0;
}
#include<stdio.h>
#include<string.h>

int main()
{
	char* p = "abcdef";//字符串末尾隐藏着\0

	printf("%zd\n", strlen(p));//6
	printf("%zd\n", strlen(p + 1));//5
	//printf("%zd\n", strlen(*p));//*p,非法访问
	//printf("%zd\n", strlen(p[0]));//p[0]->*(p+0)->*p,非法访问
	printf("%zd\n", strlen(&p));//取得指针变量p的地址,是随机值
	printf("%zd\n", strlen(&p + 1));//取得跳过这个字符串的地址,是随机值
	printf("%zd\n", strlen(&p[0] + 1));//等同于p[1]指向的b的地址,5

	return 0;
}

二维数组

#include<stdio.h>
int main()
{

	int a[3][4] = { 0 };

	printf("%zd\n",sizeof(a));//48,a是数组名,这里sizeof(a)中的a表示整个数组,计算的是整个数组大小
	printf("%zd\n",sizeof(a[0][0]));//4,计算第一行第一列元素
	printf("%zd\n",sizeof(a[0]));//16,a[0]作为第一行数组名,单独放在sizeof内部,就是计算第一行元素,第一行一共四列,即四个元素
	printf("%zd\n",sizeof(a[0] + 1));//4/8,a[0]并未单独放在sizeof内部,表示首元素地址,即& a[0][0]加一后就是& a[0][1],是地址就是4/8字节

	printf("%zd\n",sizeof(*a[0] + 1));//4,a[0] + 1是a[0][1]的地址,再解引用就是元素a[0][1]
	printf("%zd\n",sizeof(a + 1));//4/8,a+1是第二行的地址,地址就是4/8字节

	printf("%zd\n",sizeof(*(a + 1)));//16,计算的是第二行的元素

	printf("%zd\n",sizeof(&a[0] + 1));//4/8,&a[0] + 1是第二行的地址,地址就是4/8字节
	printf("%zd\n",sizeof(*(&a[0] + 1));//16,&a[0] + 1是第二行的地址,再解引用就是第二行

	printf("%zd\n",sizeof(*a));//16,a是第一行的地址,*a就是计算第一行
	printf("%zd\n",sizeof(a[3]));//16,类似于a[0],a[2]
	
	//sizeof是根据类型来计算的长度的,即使只是一个表达式,编译器也会推算出最终的类型,来计算长度

	return 0;
}

标签:arr,int,C语言,----,zd,地址,printf,sizeof,指针
From: https://blog.csdn.net/2401_88328558/article/details/144069696

相关文章

  • Easyexcel(7-自定义样式)
    相关文章链接Easyexcel(1-注解使用)Easyexcel(2-文件读取)Easyexcel(3-文件导出)Easyexcel(4-模板文件)Easyexcel(5-自定义列宽)Easyexcel(6-单元格合并)Easyexcel(7-自定义样式)注解@ContentStyle用于设置内容格式注解,可作用于类和字段上dataFormat:日期格式hidden:设置单元格使用此样......
  • python进阶之函数
    python进阶之函数函数概念函数本质声明和调用函数参数位置参数默认参数关键字参数可变参数作用域`LEGB`函数返回值return常用的内置函数函数概念函数是一段可重复使用的代码块,它接受输入参数并返回一个结果。函数可以用于执行特定的任务、计算结果、修改数据等,使......
  • 为什么很多工程企业的软件系统最后都是形象工程?拒绝“花架子”!蓝燕如何做好工程项目管
    在工程项目管理的现代化进程中,不少企业引入了各种管理软件,以期优化工作流程、提升管理效率。然而,许多企业投入巨资建设的系统最终却沦为“形象工程”,成为看似功能齐全却缺乏实用性的“花架子”。这究竟是什么原因导致的?蓝燕云作为深耕工程项目管理领域多年的系统供应商,又是如何......
  • 【IEEE独立出版 | 厦门大学主办】第四届人工智能、机器人和通信国际会议(ICAIRC 2024,12
    第四届人工智能、机器人和通信国际会议(ICAIRC2024)20244thInternationalConferenceonArtificialIntelligence,Robotics,andCommunication重要信息会议官网:www.icairc.net三轮截稿时间:2024年11月30日23:59录用通知时间:投稿后1周左右会议检索:IEEE......
  • Go实战全家桶之二十:GO RPC CLIENT聚合
    packageclientimport("git.ichub.com/general/webcli120/goconfig/base/basedto""git.ichub.com/general/webcli120/goconfig/gogrpc/gorpcclient"proto"website-grpc/gorpc/proto/hello"websiteproto"website-......
  • 前端Symbol的常见用法
    文章目录前端Symbol介绍及其常见用法一、Symbol函数的创建二、Symbol的常见用法三、Symbol的注意事项前端Symbol介绍及其常见用法Symbol是ES6中新增的一种基本数据类型,它表示独一无二的值。在前端开发中,Symbol具有多种用途,可以用于创建唯一对象属性名、定义对象的......
  • w~视觉~合集25
    我自己的原文哦~  https://blog.51cto.com/whaosoft/12627822#MeanShift简单的介绍 MeanShift的数学原理和代码实现,基于均值漂移法MeanShift的图像分割MeanShift算法简介从分割到聚类对于图像分割算法,一个视角就是将图像中的某些点集分为一类(前景),另外一些点集......
  • 操作系统三种处理机调度算法介绍
    以下是对先来先服务(FCFS)、短作业优先(SJF)、高响应比优先(HRRN)详细介绍:先来先服务(FCFS)算法•算法原理:按照作业或进程到达系统的先后顺序进行调度,先到达的先被服务,就如同日常生活中排队办事一样,先来的人先得到处理。•计算步骤:1.记录每个作业(或进程)的到达时间和服务时间(即执......
  • 网络安全-自学笔记
    目录相关网站推荐WEB(应用)安全学习路线推荐书籍网站在线靶场基础XSS攻击CSRF漏洞劫持攻击点击劫持SSRF漏洞文件包含漏洞文件上传漏洞XXE漏洞WebShell解析安全RCE漏洞SQL注入漏洞反序列化漏洞条件竞争通信安全应用层传输层网络层身份认证与访问控......
  • Rust中怎样实现链式调用?
    在Rust中,链式调用是通过方法调用返回self或者&self/&mutself来实现的。这种方式允许多个方法在一行内连续调用,非常适合构建器模式或函数式风格的代码。基础知识•self:表示所有权转移。调用后,原来的实例不能再使用。•&self:表示方法可以通过不可变引用调用。......