C语言学习笔记(一)
一、关于vs编译器中对scanf的报错问题
(1)正常情况下的代码:
int num1 = 0;
int num2 = 0;
int sum;
scanf("%d%d",&num1,&num2);
sum = num1 + num2;
printf("sum的结果 = %d",sum);
此时编译器就会报错,如下图所示:
它告诉我们要使用 scanf_s 来代替 scanf。
如何解决这个错误呢?
①按照它的要求使用scanf_s这个函数
scanf_s("%d%d",&num1,&num2);
但是这样有个缺点,你的代码只能在vs里运行,换了编译器就无法编译了,其他的编译器并不认识scanf_s
scanf_s 并不是标准C语言提供的函数,而是 vs 编译器自己提供的,标准C语言只提供了 scanf 函数,所以才会导致代码到其他编译器会无法运行。
②上图有段划线部分,前面的大概意思:“要使这个错误无效就使用”后面那一句代码。
用法:在源文件开头第一行加上这一句代码就可以了。
#define _CRT_SECURE_NO_WARNINGS
(2)这个时候就会有人觉得,每次都要加上这么一句话有点麻烦,下面就有一个解决方法:
第一步:下载一款软件:Nptepad++
找到 vs 编译器所在文件路径
我的路径是:Program Files(x86) -- Microsoft Visual Studio -- 2019 -- Community -- Common7 -- IDE -- VC -- vcprojectitems -- newc++file.cpp
总之最终的目的是找到 newc++file.cpp 这个文件
第二步:右键 newc++file.cpp 用 Notepad++ 打开,把代码 #define _CRT_SECURE_NO_WARNINGS 写进去保存即可。
(注:用记事本的话会无法访问)
二、常量、转义字符、字符串
(1)常量:
常量分为:字面常量、const修饰的常变量、#define定义的标识符常量、枚举常量
①字面常量
3;
4;
5;
像这样的叫做字面常量
②const修饰的常变量
普通的变量:
int num = 4;
printf("%d\n",num);
num = 5;
printf("%d\n",num);
运行结果:
4
5
用const修饰的常变量
const int num = 4;
printf("%d",num);
运行结果:4
如果还像上面的代码一样修改num的值,编译器就会报错 “表达式必须是可修改的左值”。
③#define定义的标识符常量
#include <stdio.h>
#define Max 10
int main()
{
printf("%d\n",Max);
return 0;
}
运行结果:10
④枚举常量
枚举就是一一列举的意思
enum Sex
{
MALE,
FEMALE,
SECRET
};
int main()
{
printf("%d\n",MALE):
printf("%d\n",FEMALE):
printf("%d\n",SECRET):
return 0;
}
运行结果:
0
1
2
enum是枚举关键字,要特别注意花括号后要加 ;
拓展:
const修饰的常变量与数组:
int n = 10;
int arr[n] = {0};
这是错误的,因为 n 是常量,C语言规定数组中括号内应为常量。
那我用 const 修饰一下 n 是不是就可以了呢?
const int n = 10;
这样也是不行的,此时的 n 只是具有常属性,但本质上还是变量。
(2)转义字符:
(1)转义字符 ‘\0‘ 的重要性:
代码一:
char arr[] = {'a','b','c'};
printf("%s\n",arr);
运行结果:
abc烫烫桃妹B s
代码二:
char arr[] = {'a','b','c','\0'};
printf("%s\n",arr);
运行结果:
abc
为什么会出现代码一的结果?
原因很简单,这里我们要明白 ‘\0’ 的意思,它是字符串的结束标志,当编译器检测到 ‘\0’ 时就结束不再往下读,明显代码一在读完 s 后才检测到 ‘\0’ ,而在代码二我们手动添加了 ‘\0’ ,所以运行结果和我们预期的一样。(注:‘\0’ 是不作为字符串的内容的)
(2)计算字符串的长度:
用到 strlen()函数,对应的头文件是 <string.h>
char arr[] = "abc";
printf("%d\n",strlen(arr));
运行结果:3
a算一个字节 ; b算一个字节 ; c算一个字节 ; \0不作为字符串中的内容所以不计算大小,故结果是 3
char arr[] = {'a','b','c'};
printf("%d\n",strlen(arr));
运行结果:随机数
如果改成 char arr[] = {'a','b','c','\0'}; 结果就是 3
char arr[] = {'a','b','c','\0'};
char arr1[] = "abc";
printf("%d\n",sizeof(arr));
printf("%d\n",sizeof(arr1));
运行结果:
4
4
可以看出strlen计算字符串长度时没有把‘\0’计算进去,而sizeof把‘\0’计算进去了,这里就涉及到sizeof与strlen的区别了,sizeof是一个关键字,而strlen是一个函数,对sizeof而言,因为缓冲区已经用已知字符串进行了初始化,其长度是固定的,所以sizeof在编译时计算缓冲区的长度。也正是由于在编译时计算,因此sizeof不能用来返回动态分配的内存空间大小。
(3)转义字符的用法:
printf("c:\test\32\test.c");
运行结果:c: est→ est.c
为什么编译器输出的和我们预期的不一样呢?
原因:\t 是一个转义字符,水平制表符,它的作用和键盘上的 Tab 键一样,导致 c : 后空了一大行;
那 → 又是哪里来的呢,这里涉及到另一个转义字符:\ddd (ddd表示1~3个八进制的数字。如 \103),所以 \32 中的32是两个八进制数,编译器会把它们转成十进制然后在ASCII码中找到值对应的字符。
八进制 32 转成十进制算法:
3 2
权重相加:3×8^1 + 2×8^0 = 24 + 2 = 26
由表可知,十进制26 对应的字符就是 →
解决方法:
printf("c : \\test\\32\\test.c");
运行结果:
c : \test\32\test.c
\\:用于表示一个反斜杠,防止它被解释为一个转义序列符
\":printf("%c\n",'\''); 运行结果:'
\':printf("%c\n","\""); 运行结果:"
\xdd:dd表示 2 个十六进制数字
printf("%c\n",'\x61');
运行结果:a
十六进制 61 转成十进制算法:
6 1
权重相加:6×16^1 + 1×16^0 = 96 + 1 = 97
十进制数 97 对应ASCII码表的字符 是 a
拓展:
一道笔试考题
请问此段代码的运行结果:
printf("%d\n",strlen("c : \test\32\test.c"));
正确结果:13
解析:\t 、\32 分别算一个字节,其余的每个字符算一个字节,共13个字节