数组,指针,字符串(C语言基础知识学习二)

系列文章目录

第一章 C语言基础知识学习一(printf,scanf,数组) link.

第二章 C语言基础知识学习二 (数组、指针)



前言

记录在极客时间中胡光老师的编程入门课程学习中遇到的难懂,还没有掌握的知识点,加以总结巩固,以便后续复习


第一题 关于数组和函数的思考

比较两个概念的异同点:

  1. 一个整型数组元素
  2. 一个传入整型并返回整型的函数

比较两个概念的异同点:

  1. 概念太过于抽象,知识储备不够,没办法具体的说出两者有什么区别,第一想法就是数组就是数组,函数就是函数,两个不同的概念,有联系吗?
  2. 按照胡光老师的说法,具体化一下可能更加能够方便理解,示意代码所示:
int arr[100] = {0, 2, 4, 6, 8, 10, ...}; 
int func(int x) {
    return 2 * x;
}
  1. 不同点:两者的本质不一样。
    • arr 是数组,对于代码 arr[36], 相当于访问数组下标 36 的位置中存储的整型值;
    • func 是函数,对于代码 func(36) 来说,也会得到一个整型值,但是这个整型值,是由 func 的函数逻辑代码计算得到的。
    • 总结来说,对数组arr 中的值进行访问,是一个静态的过程,而对于 func 函数得到返回值的过程来说,是一个动态计算的过程。
    • 时间效率,通常来说是数组访问速度要比函数计算速度快很多。
    • 空间效率,函数通常要比数组节省很多存储空间,就像 func 函数的值,是动态计算得到的,通常情况下,不管我们代码中执行 func(100) 还是 func(10000),我们不需要修改函数的代码。但对于 arr 数组来说,当我们需要访问 arr[100] 的时候,数组最起码要有 101 个元素空间,而当我们想要访问 arr[10000] 的时候,数组最起码要有 10001 个元素空间。
    • 总的来说,就是函数比数组更加节省空间,数组比函数呢,得到结果的速度更快。
  2. 相同点:在使用者看来,func(100) 和 arr[100] 的作用是完全一样的,区别可能只是中括号和小括号的区别。
    • 简单来说,就是在数学里,函数做的事情就是“映射”,传入一个值,传出一个值。在程序中也不例外,函数做的事情,就是从传入值到传出值的映射。而数组做的事情呢,其实是从下标到存储值的映射。你会发现,数组和函数做的事情,本质上都是映射!
    • “函数是压缩的数组,数组是展开的函数”,也就是说当你可以用数组进行程序的时候,你也可以使用某个能够完成相同映射功能的函数来进行替代。
  3. 二者在程序设计方面的差别,就在于时间和空间的使用效率,数组在时间效率方面占优势,函数在空间效率方面占优势。
  • 备注:上述分析来自极客时间胡光老师的编程入门相关课程,我拿过来作为自己的学习笔记总结。相关链接: link.

第二题 字符串信息转换成整型数字

1. 要求:

如下能够转化任意个整型参数的my_scanf()函数

  1. )条件:任意个参数,可变参函数
  2. )注意负数的情况
//输入输出示例代码
int n = 98, m = 0;
my_scanf("123 45", &n, &m);
printf("n = %d m = %d", n, m); // 输出 n = 123 m = 45

2. 代码实现:

/*
** 要求:能够转化任意个整型参数的my_scanf()函数
** 条件1:任意个参数,可变参函数
** 条件2:注意负数的情况
*/ 
//#define va_list char*   /* 可变参数地址 */
//#define va_start(ap, x) ap=(char*)&x+sizeof(x) /* 初始化指针指向第一个可变参数 */
//#define va_arg(ap, t)   (ap+=sizeof(t),*((t*)(ap-sizeof(t)))) /* 取得参数值,同时移动指针指向后续参数 */
//#define va_end(ap)  ap=0 /* 结束参数处理 */

#include <stdio.h>
#include <stdarg.h>
void my_scanf(const char *string, ...);
int main(void){
	int n = 98;
	int m =10;
	int k = 2;
	int j = 20;
	
	my_scanf("-12 3 -45 60 ", &n, &m, &k, &j);
	printf("the number is %d\t%d\t%d\t%d\n", n, m, k, j);
	return 0;
} 

void my_scanf(const char *string, ...){
	int number = 0;
	char flag;
	const char *p;
	int  *q;
	
	va_list ap;//定义可变参数指针,即为char *ap; 
	va_start(ap, string); //初始化指针ap,指向第一个可变参数 
	for(p = string; *p != '\0'; p++){
		if(*p != ' '){
			if(*p == '-'){
				flag = 1;
				continue;
			} 
			number = number * 10 + (*p - '0');
		}else{
			q = va_arg(ap, int*);
			if(flag) {
				flag = 0;
				number = -number;
			}
			*q = number;
			number = 0;
		}	
	}
	va_end(ap);
}

3. 归纳总结:

  1. 数字字符转化为对应整数:打比方说将字符’9’转化成对应的整型数字9,可以利用’0’字符进行转化,然后转化成整型输出,就是该字符对应的整型数字
#include <stdio.h>
int main(void){
	char a = '9';
	printf("the number is %c %d\n", a, a - '0');
	return 0;
}
  • 代码运行结果: 在这里插入图片描述
  1. 可变参函数的实现原理与过程
    1. 这种函数最典型应用的代表就是printf和scanf了,先看几个宏定义:
    1. typedef char * va_list;
    2. #define _INTSIZEOF(n)       ( (sizeof(n)+sizeof(int)-1) & ~(sizeof(int)-1) )
    3. #define va_start(ap,v)        ( ap = (va_list)&v + _INTSIZEOF(v) )
    4. #define va_arg(ap, type)    ( *(type *)((ap += _INTSIZEOF(type)) - _INTSIZEOF(type)) )
    5. #define va_end(ap)             ( ap = (va_list)0 )
  1. 分别解析一下每个宏定义的作用
    1. ( (sizeof(n)+sizeof(int)-1) & ~(sizeof(int)-1) )
      一般来说,sizeof(int)在32位系统中大小是4,那么上面表达式就可以化简为 ( (sizeof(n)+3) & ~3 ),
      其中对3取反即为 1111 1111 1111 1100那么可以观察到一个比3大的数字,与3的相反数按位与,其结果一定是4的倍数
      所以这个宏存在的意义就是针对某些系统需要内存地址对齐,也就是参数在内存中的地址均为sizeof(int)=4的倍数。
    2. #define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
      其中ap为字符型指针变量,v表示可变参函数的第一个固定参数,那么上述表达式中 (va_list)&v表示取得第一个固定参数的地址,_INTSIZEOF(v)表示固定参数所占内存的大小,然后两者相加就是表示第一个可变参数的地址。
    3. #define va_arg(ap, type) ( *(type *)((ap += _INTSIZEOF(type)) - _INTSIZEOF(type)) )
      分成两部分看,首先ap += _INTSIZEOF(type),表示ap指向下一个可变参数的地址,然后ap - _INTSIZEOF(type),表示当前可变参数的地址
    4. #define va_end(ap) ( ap = (va_list)0 )
      va_end宏使ap不再指向有效的内存地址。该宏的某些实现定义为((void*)0),编译时不会为其产生代码,调用与否并无区别。但某些实现中va_end宏用于函数返回前完成一些必要的清理工作:如va_start宏可能以某种方式修改堆栈,导致返回操作无法完成,va_end宏可将有关修改复原;又如va_start宏可能对参数列表动态分配内存以便于遍历va_list,va_end宏可释放此前动态分配的内存。因此,从使用va_start宏的函数中退出之前,必须调用一次va_end宏。参考: link.

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yaoji1234

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值