C语言学习笔记(一)

一、关于vs编译器中对scanf的报错问题

       1正常情况下的代码:

int num1 = 0;
int num2 = 0;
int sum;
scanf("%d%d",&num1,&num2);
sum = num1 + num2;
printf("sum的结果 = %d",sum);

       此时编译器就会报错,如下图所示:

       初识C语言(一)_C语言学习笔记 

       它告诉我们要使用 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

       初识C语言(一)_C语言学习笔记_02

       由表可知,十进制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个字节