目录
注释符号
其他注释方法
注释建议
接续符和转义符
在续行符\之前或者之后带上空格,行不行?
\n:换行符与\r:回车符之间的区别
两个小程序(旋转光标、倒计时)
单引号和双引号
编辑'abcd'这样写有问题吗?
特殊情况
为何计算机需要字符
逻辑运算符
短路
位运算符
&& vs &、|| vs |的区别
注释符号
在C语言中,注释指的是在程序代码中添加的一些说明或标记,这些注释并不会被编译器解析和执行,仅仅是为了帮助程序员更好地理解代码。
C语言中支持两种注释方式:
1. 单行注释:使用“//”符号标记注释内容,从“//”开始到该行结尾处都被视为注释,编译器会忽略这些内容。
例如:
2. 多行注释:使用“/*”和“*/”符号包含多行注释内容,从“/*”开始到“*/”结束的所有内容都被视为注释,编译器会忽略这些内容。
例如:
注释是一种很重要的编程技巧,它可以增强代码的可读性和可维护性,方便其他人或自己在之后修改代码。
#include<stdio.h>
int main()
{
int /* */ i; //正确
char* s = "abcd //xyz"; //正确
//Is it a\
valid comment? //正确
in/* */t j; //报错
return 0;
}
注意:注释被替换,本质是替换成空格。
# 和 define之间是可以带空格的。
1.c语言风格注释无法嵌套
2./*总是与离它最近的*/匹配
其他注释方法
//基于条件编译,代码编译期间处理
#include <stdio.h>
#define MONEY 0
int main()
{
#if MONEY
printf("for test1\n"); //test1
printf("for test2\n"); //test2
#endif
return 0;
}
//基于if判断,代码运行期间处理
#include <stdio.h>
int main()
{
//if (0)注释方法
if (0) {
printf("for test1\n"); //test1
printf("for test2\n"); //test2
}
return 0;
}
注释建议
复杂的函数中,在分支语句、循环语句结束之后需要适当的注释,方便区分各分支或循环体。
接续符和转义符
在C语言中,续行符和转义符都是用来对特殊字符进行处理和表示的。它们的作用与用途是不同的,下面我来简单解释一下:
1. 续行符
续行符是用来将一行过长的代码分割成多行的特殊字符,以便于阅读和编写。在C语言中,续行符使用反斜线符号“\”来表示,用在需要跨行的地方的末尾处。
例如:
使用续行符后,上面的代码可以分为三行来编写,其结果和不使用续行符的代码是一样的。
2. 转义符
转义符是用来表示一些特殊字符的符号。在C语言中,转义符使用反斜线符号“\”配合后面的字符来表示,常用的转义符有:
- \n:表示换行符
- \t:表示制表符
- \r:表示回车符
- \0:表示字符串结束标志符需要注意的是,在字符串中使用引号时,需要使用转义符来表示引号自身,例如:
上面的代码使用了转义符“\”来表示引号自身,因为在字符串中使用引号会引起歧义。
在续行符\之前或者之后带上空格,行不行?
C中,有一些字符,就是他的字面意思,比如'n','b','t'。
也有一些字符,本身就是特殊含义的,比如:" , ', \
转义的本质含义是:字面转特殊,或者特殊转字面。
在第6行中,出现了一个编译错误,因为在printf函数中缺少一个右括号)。该行代码的目的是要输出一个双引号,但是,由于双引号也是C语言中的特殊字符,因此需要在前面加上一个反斜杠\,来表示它是一个字面量,而不是代码中的引号。
在第7行中,出现了一个特殊字符转义序列\",它表示输出一个双引号。
在第8行中,使用了特殊字符转义序列\n,它表示输出一个换行符。
在第9行中,使用了特殊字符转义序列\t,它表示输出一个制表符。
\n:换行符与\r:回车符之间的区别
在计算机文本文件中,"\n"代表换行符(Line Feed),通常被译为"新行"。而"\r"代表回车符(Carriage Return),通常被译为"回车"。
在早期的打印机、终端设备中,换行和回车都是必须的操作。当需要让打印头或光标移动到下一行的开头时,需要先执行回车操作,然后再执行换行操作。这种习惯一直延续下来,即"回车+换行"的序列被用作一个行的结束和下一行的开始标志。
但是在现代的计算机系统中,通常只需要用到换行符。因此,当我们在Windows系统中使用记事本编辑文本文件时,换行符和回车符会被同时输出,但是在其他平台上,如Linux、Mac等,只会输出换行符。
简单来说,换行符是让光标移到下一行的开头,而回车符是让光标移到本行的开头。但是,现在通常只需要用换行符就可以了。
两个小程序(旋转光标、倒计时)
旋转光标
#include<stdio.h>
#include<windows.h>
#include<string.h>
int main()
{
int index = 0;
const char* label = "|/-\\";//由于\是特殊字符,需要转义成字面字符
//printf("%d\n", strlen(label));//4 - 个字符
while (1)
{
index %= 4;
printf("[%c]\r", label[index]);
index++;
Sleep(1000);
}
return 0;
}
这段代码是一个简单的命令行动画,通过不断地输出字符 "|/-\\" 实现一个不断旋转的动画效果。具体来说:
1. 在 main 函数中定义变量 index,用于表示当前应该输出那个字符;
2. 定义常量指针 label,指向字符数组 "|/-\\",存储了要输出的四个字符;
3. 使用一个 while 循环,不断执行以下操作:
4. 使用取模运算符将 index 的值限制在 0~3 之间,确保 index 不会越界;
5. 使用 printf 函数输出格式化字符串 "[%c]\r",其中 %c 表示要输出的字符,\r 表示将输出的光标移回行首,以便下一次输出覆盖当前输出;
6. 将 index 值加 1,以便下一次循环时输出下一个字符;
7. 使用 Sleep 函数暂停一段时间,以便动画效果更显著;
8. 循环回到第 4 步,继续输出动画。
倒计时
#include<stdio.h>
#include<windows.h>
int main()
{
int i = 9;
for (i = 9; i >= 0; i--)
{
printf("[%d]\r", i);
Sleep(1000);
}
return 0;
}
这段代码是一个简单的倒计时程序,通过循环输出数字并使用 Sleep 函数暂停一段时间,实现倒计时效果。具体来说:
1. 在 main 函数中定义变量 i 并初始化为 9,用于表示当前的倒计时值;
2. 使用 for 循环从 9 开始倒数,一直到 0;
3. 在循环体中,使用 printf 函数输出格式化字符串 "[%d]\r",其中 %d 表示要输出的数字,\r 表示将输出的光标移回行首,以便下一次输出覆盖当前输出;
4. 使用 Sleep 函数暂停一秒钟,以便倒计时效果更显著;
5. 循环回到第 3 步,输出下一个数字,直到倒计时结束;
6. for 循环结束后,程序返回 0,表示正常结束。
单引号和双引号
在 C 语言中,单引号和双引号都是用于表示字面量的符号。
1. 单引号:单引号括起来的字符表示字符字面量,比如 'a', 'b', '1' 等。在程序中使用时,单引号里的字符会被编译器转换成该字符的 ASCII 码或 Unicode 码,如 'a' 对应的 ASCII 码是 97,可以用整型变量存储。
示例:char c = 'a';
2. 双引号:双引号括起来的内容表示字符串字面量,比如 "hello","world" 等。在程序中使用时,双引号里的字符串会被编译器转换成一个字符数组,以空字符 '\0' 结尾。
示例:char s[] = "hello world";
需要注意的是,单引号和双引号在 C 语言中是有区别的,不能混淆。在 C 语言中,两者不能互换使用。
//单引号是字符,双引号是字符串
#include <stdio.h>
//不同编译器,会有细微的差别
int main()
{
printf("%d\n", sizeof(1));
printf("%d\n", sizeof("1"));
//C99标准的规定,'a'叫做整型字符常量(integer character constant),被看成是int型
printf("%d\n", sizeof('1'));
char c = '1';
printf("%d\n", sizeof(c));
return 0;
}
这段代码主要演示了 C 语言中单引号和双引号的一些不同用法和特性。具体来说:
1. printf("%d\n", sizeof(1));:sizeof 运算符可以用于计算表达式或数据类型的大小,这里使用 sizeof(1) 计算整型常量 1 的大小,得到结果为 4,因为在大多数 C 语言实现中,整型常量都被视为 int 类型,占用 4 个字节。
2. printf("%d\n", sizeof("1"));:使用 sizeof("1") 计算字符串字面量 "1" 的大小,结果为 2,因为字符串字面量中除了字符本身还会包含一个结尾的空字符 '\0',所以实际大小为 2 个字节。
3. printf("%d\n", sizeof('1'));:使用 sizeof('1') 计算字符字面量 '1' 的大小,结果为 4,因为字符字面量 '1' 被视为整型字符常量,类型为 int,占用 4 个字节。
4. char c = '1'; printf("%d\n", sizeof(c));:定义一个 char 类型的变量 c,初始化为字符字面量 '1',使用 sizeof(c) 计算变量 c 的大小,结果为 1,因为 char 类型占用 1 个字节。这里的字符字面量 '1' 被视为整型字符常量,只不过把整型4个字节数据写到1个字节里,这里一直在发生截断。
需要注意的是,在不同的编译器和不同的标准下,对于整型字符常量和字符字面量的处理方式可能存在差异,建议按照标准的规定使用。下图分别是是gcc和vs编译环境下的结果。
'abcd'这样写有问题吗?
#include<stdio.h>
#include<windows.h>
int main()
{
"";
'';//error C2137: 空字符常量
"a";
'a';
"abcd";
'abcd';//?
char c = 'abcd';//warning C4305: “初始化”: 从“int”到“char”截断
printf("%c\n", c);// d
c = 'abcdef';// error C2015: 常量中的字符太多
c = 'abc';
printf("%c\n", c);// c
return 0;
}
这段代码主要演示了 C 语言中字符串和字符字面量的使用和一些细节问题。具体来说:
1. "" 和 "a":这是两个字符串字面量,分别表示空字符串和包含一个字符 'a' 的字符串。在编译时,C 语言编译器会将字符串字面量转换为字符数组,因此在程序中可以像使用字符数组一样使用字符串字面量。
2. '' 和 'a':这是两个字符字面量,分别表示字符 'a' 和空字符,即不含任何字符的字符字面量。需要注意的是,在 C 语言中,字符字面量必须包含一个字符,因此使用单引号括起来的空字符是错误的语法。
3. "abcd" 和 'abcd':这是正确的语法,字符串字面量 "abcd" 包含 5 个字符(包括结尾的空字符),而字符字面量 'abcd' 被定义为 int,4个字节可以存放数据。
4. char c = 'abcd';:这是合法的语法,但是编译器会发出警告(warning),提示将 int 类型的整数截断为 char 类型。实际上,在 C 语言中,字符常量的类型被定义为 int,因此使用 char 类型的变量存储字符常量时,会发生类型截断。
5. c = 'abcdef';:这是错误的语法,因为字符字面量 'abcdef' 包含了多个字符,已经超过了int类型的字节数。。
6. c = 'abc';:这是合法的语法,但是编译器会发出警告(warning),提示将 int 类型的整数截断为 char 类型。实际上,在 C 语言中,字符常量的类型被定义为 int,因此使用 char 类型的变量存储字符常量时,会发生类型截断。
需要注意的是,使用字符串和字符时,需要注意其长度和类型,避免出现类型不匹配或越界访问等问题。
特殊情况
为何计算机需要字符
计算机需要字符是因为字符是人类交流和存储信息的基本单位之一。在计算机的发展历史中,最初的计算机只能处理数值数据,无法处理字符和文本信息,这限制了计算机在人机交互和信息处理方面的应用。
在计算机中,所有的数据都是以二进制的形式存储和处理的,即由0和1两种状态来表示信息。但计算机所表示的信息类型很多,比如文字、图像、声音等,如果直接使用0和1来表示这些信息显然是不太现实的,因此我们需要一种将这些信息转化为二进制的方法,并且能够让计算机正确地将其解码回来的方法。
这时就出现了字符编码,它是一种将文字、数字、符号等字符转化为计算机可识别的二进制数的方法。常用的字符编码有ASCII码和Unicode码,它们可以将每一个字符都映射到一个独一无二的二进制数上。
例如,在ASCII码中,每个字符都被映射到一个包含7个二进制位的数字上,可以表示128种不同的字符,包括英文字母、数字和标点符号等。而在Unicode码中,每个字符则被映射到一个包含16个二进制位的数字上,可以表示超过13万种不同的字符,包括各种语言的文字、符号和表情等。
通过使用字符编码,计算机可以正确地将输入的文字、图像、声音等信息转化为二进制,并在需要的时候将其解码回来,实现信息的存储、处理和显示等功能。
逻辑运算符
C语言中的逻辑运算符有两种,分别为逻辑与(&&)和逻辑或(||)。它们的作用如下:
1.逻辑与(&&):如果两个操作数都为真,则表达式的值为真;否则,表达式的值为假。
2.逻辑或(||):如果两个操作数中至少有一个为真,则表达式的值为真;否则,表达式的值为假。
//级联两个(多个)逻辑表达式,必须同时为真,结果才为真
//与&(按位与)是不同的概念
#include <stdio.h>
int main()
{
int i = 0;
int j = 0;
//前置++ i先自增,再使用
if ((++i < 0) && (++j > 0)) {
printf("enter if!\n");
}
printf("%d, %d\n", i, j); //1, 1
return 0;
}
//级联两个(多个)逻辑表达式,必须至少一个为真,结果才为真
//与|(按位或)是不同的概念
#include <stdio.h>
#include <windows.h>
int main()
{
int i = 0;
int j = 0;
//发生短路:一个条件为真,已经不需要在看后续的条件的情况
if ((++i > 0) || (++j > 0)) { //注意更改条件
printf("enter if!\n");
}
printf("%d, %d\n", i, j); // 1, 0
system("pause");
return 0;
}
短路
逻辑运算符有一个特点,即只要能够确定整个表达式的值,就会立即停止计算。这个特点称为“短路”,执行顺序是从左到右的。主要体现在以下两种情况:
1. 对于逻辑与(&&)来说,如果第一个操作数为假,则整个表达式的值一定为假,所以不会再去计算第二个操作数,直接返回假。
2. 对于逻辑或(||)来说,如果第一个操作数为真,则整个表达式的值一定为真,所以不会再去计算第二个操作数,直接返回真。
#include <stdio.h>
int show()
{
printf("you can see me!\n");
return 1;
}
int main()
{
int a = 0;
scanf("%d", &a);
a == 10 && show();
return 0;
}
这段代码的功能是判断用户输入的数是否等于10,如果等于,则调用函数show()。如果不等于,则不会调用该函数。
具体分析如下:
1. 定义了一个函数show(),其功能是输出一段文字并返回1。
2. 在主函数中,定义了一个整型变量a,从用户输入中获取值。
3. 判断a是否等于10,并用逻辑与运算符连接show()函数的调用。由于逻辑与(&&)具有短路特性,所以只有在a等于10时,才会调用show()函数。
4. 最后返回0,表示程序运行正常结束。
#include <stdio.h>
int show()
{
printf("you can see me!\n");
return 1;
}
int main()
{
int a = 0;
scanf("%d", &a);
a == 10 || show();
return 0;
}
这段代码的功能是判断用户输入的数是否等于10,如果不等于10,则调用函数show()。如果等于10,则不会调用该函数。
具体分析如下:
1. 定义了一个函数show(),其功能是输出一段文字并返回1。
2. 在主函数中,定义了一个整型变量a,从用户输入中获取值。
3. 判断a是否等于10,并用逻辑或运算符连接show()函数的调用。由于逻辑或(||)具有短路特性,当a不等于10时,才会调用show()函数。
4. 最后返回0,表示程序运行正常结束。
位运算符
C语言中的位运算符可以直接操作二进制数的每一位,包括按位与(&)、按位或(|)、按位异或(^)、按位取反(~)。
1. 按位与(&):两个相应的二进制位都为1时,结果为1;否则,结果为0。
2. 按位或(|):两个相应的二进制位都为0时,结果为0;否则,结果为1。
3. 按位异或(^):两个相应的二进制位不同时,结果为1;否则,结果为0。
4. 按位取反(~):对操作数的每一位取反,即0变成1,1变成0。
#include <stdio.h>
int main()
{
/*
2的补码:0000 0000 0000 0000 0000 0000 0000 0010
3的补码:0000 0000 0000 0000 0000 0000 0000 0011
*/
//|:两个相应的二进制位都为0时,结果为0;否则,结果为1。
// 0000 0000 0000 0000 0000 0000 0000 0011 - 3
printf("%d\n", 2 | 3);
//&:两个相应的二进制位都为1时,结果为1;否则,结果为0。
// 0000 0000 0000 0000 0000 0000 0000 0010 - 2
printf("%d\n", 2 & 3);
//^:两个相应的二进制位不同时,结果为1;否则,结果为0。
// 0000 0000 0000 0000 0000 0000 0000 0001 - 1
printf("%d\n", 2 ^ 3);
//~:对操作数的每一位(包括符号位)取反,即0变成1,1变成0。
// 1111 1111 1111 1111 1111 1111 1111 1111 - 补码
// 1111 1111 1111 1111 1111 1111 1111 1110 - 反码
// 1000 0000 0000 0000 0000 0000 0000 0001 - 原码 - -1
printf("%d\n", ~0);
return 0;
}
&& vs &、|| vs |的区别
&& vs &
&&:级联的是多个逻辑表达式,需要的是真假结果
& :级联的是多个数据,逐比特位进行位运算
逻辑结果:吃了吗?
数据结果:吃了多少?
|| vs | 同上