你不知道的C语言知识(第1期)

在这里插入图片描述

本期介绍🍖
主要介绍:C语言中一些大家熟知知识点中的盲区,这是第一期。



1. ASCII码

  在计算机中所有数据都是以二进制的形式进行存放的,字符也不例外。可字符怎么转换成二进制序列呢?通过给每一个字符编号,且一一对应,这样只要记住字符对应的编号就相当于存储字符,这种方法被称为编码。
  为了方便大家互相通信,不造成混乱,于是美国国家标准协会(ANSI)规定字符编号标准:ASCII码。如下图所示。

在这里插入图片描述

  1. ASCII码 48~57 表示字符 0~9
  2. ASCII码 65~90 表示字符 A~Z
  3. ASCII码 97~122 表示字符 a~z
  4. ASCII码 0~31这32个字符是不可打印字符,无法打印在屏幕上观察。

2. 转义字符

  转义字符是C语言中表示字符的一种特殊形式,通常用于表示那些无法打印字符和特定功能字符,就譬如:\n表示换行的意思,是\n的意思发生了转变。常用的转移字符如下图所示。

在这里插入图片描述

  例题:计算字符串"c:\test\121"中字符的个数。

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

int main()
{
	printf("%zd\n", strlen("c:\test\121"));
	return 0;
}

在这里插入图片描述


3. 字符串结束标志

  在C语言中,字符串末尾其实隐藏着一个\0,作为字符的结束标志。如下图所示,字符串“abcdef”的末尾其实存放着‘\0’。

在这里插入图片描述

  \0是字符串的结束标志,printf函数打印字符串和strlen函数计算字符串长度,都是通过\0来判断字符串是否结束,遇到\0的时候就自动停止了。举个例子:如果字符串后面没有\0,printf在打印该字符串时会发生什么?代码如下。

#include<stdio.h>

int main()
{
	char arr1[] = "abc";
	char arr2[] = { 'a','b','c' };
	printf("arr1 = %s\n", arr1);
	printf("arr2 = %s\n", arr2);
	return 0;
}

在这里插入图片描述

  如上图所示,arr1存放的是带\0的字符串,arr2存放的是没有带\0的字符串。可以看见,arr2字符串在打印的时候,除了打印 "abc"外还打印了"烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫贴-?近"这样的随机值,为什么会这样?因为当printf函数打印完'c'后没有遇到结束标志,会继续往后打印直到遇见第一个\0才停下来。


4. 全局变量和局部变量

  所谓局部变量就是在括号内创建的变量,全局变量就是在括号外创建的变量。如下图所示,其中a、c是局部变量,b为全局变量。

在这里插入图片描述


4.1 作用域

  作用域就是限定变量能够使用的范围,出了这个范围就无法使用了。
  全局变量的作用域是整个工程,也就是说全局变量可以在程序的任意地方使用,甚至不同的源文件都可以用同一个全局变量(但需要是用函数extern声明一下这个全局变量是外部引用)。局部变量的作用域就是变量所在的局部范围,通俗来说就是其所在那个括号的范围。
  如下图所示,printf在变量a和b作用域的范围内,所以可以正常使用。但变量c的作用域只在if语句中,printf在if语句外部不在作用域中,故无法正常使用。

在这里插入图片描述


4.2 生命周期

  生命周期在编程中指变量、函数或者其他从创建到销毁的这个时间段。
  全局变量的生命周期为整个程序,随程序的创建而创建,随程序的销毁而销毁。局部变量的生命周期是:进入作用域生命周期开始,出作用域生命周期就结束。


4.3 内存存储方式

  在C语言中内存可以被简单划分几块不同的区域:栈区、堆区、静态区…,如下图所示。其中局部变量是放置在栈区中,全局变量是放置在静态区中,堆区用于动态内存开辟。

在这里插入图片描述


4.4 局部变量与全局变量重名

  若全局变量与局部变量重命名,在局部变量作用范围内,优先使用局部变量,全局变量会被屏蔽。如下图所示。

在这里插入图片描述


5. sizeof操作符

  每一种数据类型都有自己的长度,使用不同的数据类型就能创建出不同长度的变量,变量长度不同数据的存储范围就有所差异。怎样能够直观的看到类型和存储空间呢?有这么一个操作符sizeof,同样也是一个关键字,sizeof是专门用来计算类型或变量表达式所占内存空间的大小,类型是字节。
  注意:sizeof操作符的操作数如果是类型,必须使用括号。sizeof操作符的操作数如果是表达式,则可是省略括号。

1. sizeof (类型)
2. sizeof 表达式

5.1 sizeof返回值类型

  sizeof操作符的返回值C语言只规定是无符号整数,并没有规定具体的类型,而是由编译器自己决定。在不同的编译器上sizeof的返回类型有可能是unsigned intunsigned longunsigned long long,这就导致使用printf打印sizeof的返回值,需要根据不同的编译器使用不同的占位符,不利于程序的可移植性。
  于是C语言提供了一个解决办法,创造了一个类型别名size_t,用以统一sizeof的返回值类型。size_t类型在printf中的占位符%zd


5.2 sizeof中表达式不进行计算

  sizeof操作符的操作数如果是表达式,sizeof只计算表达式的返回类型,不会执行表达式的。如下图所示,num并没有被赋值。

在这里插入图片描述


6. printf函数

6.1 输出格式

  printf是格式化的标准输出函数,所谓标准输出就是输出到屏幕上,格式化就是可以制定输出文本的格式。下面介绍一些printf函数的使用小技巧:

  1. 限定输出宽度
    在占位符%d中间加一个数字5,%5d就表述这个占位符宽度至少是5位。如果不满5位就会添加空格。
    在这里插入图片描述

  2. 输出向左、右对齐
    %5d输出的值默认是向右对齐的,想要向左对齐,只要在占位符的%后面添加-号就可以%-5d
    在这里插入图片描述

  3. 显示+/-号
    默认情况下printf是只会在输出负数时才带符号,正数是省略符号。如果想让输出正数时也带符号,只要在%5d占位符中间加个+号就可以%+5d
    在这里插入图片描述

  4. 限定小数位
    printf输出小数默认是保留小数点后6位,如果想保留2位小数,占位符可以写成%.2f。最小宽度和小数位数这两个限定值,都可以*代替,通过printf的参数传入。在这里插入图片描述

  5. 输出部分字符串
    printf在输出字符串,默认是全部输出。如果想要只输出字符串开头5个字符,占位符可以写成%.5s
    在这里插入图片描述


6.2 printf函数返回值

  printf函数是有返回值的,返回值类型为整形int。如果printf输出成功,则返回在屏幕上打印字符的个数,举个例子:printf在屏幕上打印“abc”,返回值为3。若printf输出时发生错误,则返回负数。
  下面的题目的返回值是多少?返回值是:4321。这是嵌套使用printf,把printf的返回值作为另一个printf函数的参数。

#include <stdio.h>
 int main()
 {
 printf("%d", printf("%d", printf("%d", 43)));
 return 0;
 }

7. scanf函数

  scanf是格式化的标准输入函数,所谓标准输入是指从键盘上输入,格式化就是可以制定输入文本的格式。注意:scanf参数传递的不是值,而是地址,所以变量前面必须加&取地址符号。

7.1 scanf读取用户输入原理

  scanf会把用户的输入先放入缓存中,直到用户按下回车键后,按照占位符对缓存进行解读。解读用户输入时,会从上一次解读遗留下来的第一个字符开始,直到读完缓存,或者遇到一个不符合条件的字符为止停下来。
  举个例子:若用户输入:-13.45e12# 0,下面的代码会怎么执行?当用户输入后,第一个scanf是按照整形占位符%d进行解读,从'-'开始往后读,直到遇见'.',小数点不可能出现在整数中,不符合条件停止往后读取,所以第一个scanf读到了整数-13。第二个scanf会从上一次解读遗留下拉的‘.’开始解读,由于是浮点型占位符'%f',小数点是合理的继续往后读,直到遇见'#'停下来,因为浮点数中不可能存在#号不合理,所以第二个scanf读到的是'.45e12',这里的e是代表科学计数法,即:0.45×1012。输出结果如下图所示。

#include<stdio.h>
int main()
{
	int x = 0;
	float y = 0;
	scanf("%d", &x);
	printf("%d\n", x);
	scanf("%f", &y);
	printf("%f\n", y);
	return 0;
}

在这里插入图片描述


7.2 占位符%c与%s的使用特性

  所有占位符中除了%c以外,都会自动忽略起首的空白字符。%c 不忽略空白字符,总是返回当前第⼀个字符,无论该字符是否为空格。如果要强制跳过字符前的空白字符,可以在%c 前加上⼀个空格,表示跳过零个或多个空白字符,举个例子:scanf(" %c", &ch)(所谓的空白字符就是指:空格、制表符、换行符等等)。
  占位符%s会从第一个非空白字符开始读起,直到遇见空白字符才停下来。也就是说占位符%s无法读取带空格的字符串,除非多个%s连用。还有scanf函数在使用%s输入字符串,会在字符串末尾存储一个空字符‘\0’


7.3 scanf读取时的越界访问

  scanf函数在读取字符串时,是不会考虑存储空间是否能放得下用户输入的字符串,很有可能就会导致越界访问。如图所示,arr数组只能存放5个字符,可用户却输入abcdef加上字符串末尾的结束标志\0,总共需要7个字符的空间,scanf越界访问,系统崩溃。

在这里插入图片描述

  为了防止这种情况发生,在使用%s占位符时应该指定读取字符串的最长长度,即:%5s,表示读取字符串的最大长度为5,后面的字符将被丢弃。举个例子,如下图所示。

在这里插入图片描述


7.4 赋值忽略符

  由于用户的输入可能会不符合预定的格式,举个例子:用户需要输入年、月、
日,可能会输成2024-3-3,或者2023/3/3,这种情况下scanf就必然会解析失败。为了避免这种情况,scanf提供了一个赋值忽略符*,只要把*加在任何占位符的百分号后面,该占位符就只会解析,解析完后不会返回值。如下图所示。

在这里插入图片描述


7.5 scanf的返回值

  scanf函数的返回值是一个整数,表示正确读取到变量的个数。如果没有读取到任何项,或匹配失败,则返回0。如果在成功读取任何数据之前,发生了读取错误或者遇到读取到文件结尾,则返回常量EOF(end of file文件结束标志)。
  scanf的返回值可以用于多组输入的循环条件判断,举个例子:输入两个数,比较这两个数的大小,输出较大的那个,要实现多组输入。如下图所示,只有输入ctrl+z终止符时才停下来。

在这里插入图片描述


8. 悬空else问题

  下面来看一段非常简单的代码,请问最后输出结果是hehe还是haha?

#include<stdio.h>
int main()
{
	int a = 1;
	int b = 2;
	if (a == 5)
		if (b == 2)
			printf("hehe\n");
	else
		printf("haha\n");
	return 0;
}

在这里插入图片描述

  答案是什么也没有输出,为什么会这样呢?这是因为else会和离他最近的if进行匹配,所以上题的else是与if (b == 2)匹配的,而不是if (a == 5),尽管else看上去是与第一个if对齐的。造成这种情况的本质问题是,不良的代码风格,你在读这段代码时是按照你的代码风格来看待,所以习惯的以为else是与对齐的那个if匹配的。如果养成良好的代码风格,将上题写成如下所示,别人想理解错都难。

#include<stdio.h>
int main()
{
	int a = 1;
	int b = 2;
	if (a == 5)
	{
		if (b == 2)
			printf("hehe\n");
		else
			printf("haha\n");
	}
	return 0;
}

9. 逻辑运算符的短路求值

  在C语言中提供了3个用于逻辑运算的操作符,逻辑与&&、逻辑或||、逻辑取反。其中&&运算符和||运算符还有一个特点,总是先对操作符左侧的表达式求值,再对右侧的表达式求值,这个顺序是保证的。如果左侧的表达式已经满足逻辑判断条件,就不再对右侧的表达式求值,这种情况被称为:逻辑短路
  举个例子如下图所示,逻辑与运算在判断完j++表达式结果为0后,不管&&运算符右侧的结果是什么,结果都为假,所以右侧表达式i++没有必要求值就忽略了,i的值始终保持为5。

在这里插入图片描述


10. 循环语句中的break和continue

  break用于直接终止循环,跳出循环继续执行后面的代码。continue用于跳过本次循环continue后面的代码,继续进行下一次循环。

10.1 while循环

在这里插入图片描述


10.2 do while循环

在这里插入图片描述


10.3 for循环

在这里插入图片描述


在这里插入图片描述

这份博客👍如果对你有帮助,给博主一个免费的点赞以示鼓励欢迎各位🔎点赞👍评论收藏⭐️,谢谢!!!
如果有什么疑问或不同的见解,欢迎评论区留言欧👀。

  • 30
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值