入门C语言首先要掌握的知识

148 阅读11分钟

​​​​本文已参与「新人创作礼」活动,一起开启掘金创作之路

一、变量⭐

知识点一:什么是变量🌵

顾名思义,变量就是可变的量,可以被任意的赋值和修改。与之相对的是常量,一旦被初始化之后便不可以被修改(后文会详细讲)

知识点二:如何使用变量🌕

变量的使用要遵循“先定义后使用的原则”。那什么是定义变量呢?定义变量就是创建一个对象,并根据变量的类型向内存申请相应大小的空间(如一个变量为int类型,则向内存申请4字节的空间)。我们现在创建了一个变量m,并给他初始化为10。

int main()
{
	int m = 10;
}

问题一:如果不初始化会怎么样?🤔

答:如果这个变量为全局变量,则其初始值为0。如果这个变量为局部变量,则其初始值为随机值(全局变量后文讲)。既然是随机值鬼知道他到底是多大(不看监控的话),所以在使用局部变量的时候要记得赋值,最好定义后随即跟上赋值,防止忘记赋值了。

 强行使用编译器也不会允许的

 易错一:分号

注意:新手在写代码的时候;老是会落掉。好在VS的报错够智能会即使提醒你。那有人会问分号有什么用呢?在c语言中一行表示一条语句,加上;表示这条语句的结束。

 补充一:C99之前的标准📜

在C99标准之前要求先变量定义要放在最前面。什么意思呢,现在演示一下。在C99标准下第二种写法就不正确了。但这个问题大家不用太关心,VS2013~VS2019对C99是支持的,所以以下都可以。

int main()
{
	int a=1;
	int b=1;
	b = a + 1;
	return 0;
}

int main()
{
	int a = 1;
	int b = a + 1;
	return 0;
}

 知识点三:变量的分类🌕

变量分为全局变量和局部变量。怎么区分的呢?其实很简单,在代码块外的就是全局变量,在代码块内的就是局部变量。(代码块就是“{ }”)

(里面的for语句先别管,以后会提到) 

int g_val = 1;//全局变量
int main()
{
	int i=1;//局部变量
	int count = 0;//局部变量
	for (i = 1; i < 3; i++)
	{
		int j = 1;//局部变量
		for (j = 1; j < 3; j++)
		{
			count++;
		}
	}
	return 0;
}

 建议一:全局变量

在C程序里最好少用全局变量。试想一个几万行代码的工程突然冒出来一个变量不免让人疑惑。如果一定要使用全局变量,在命名时最好加上g_,g就表示global嘛,表明它是一个全局变量,避免人们误会。

问题一:全局变量和局部变量的区别

区别一

谈到两者的区别不得不提到两个概念:作用域和生命周期

作用域:就是变量有效的范围。局部变量的作用域在它所在的代码块范围内

……{   { int i {  { …… } } }  }如这里i在随后的两个代码块里都是可以用的,但是在最外面的代码块已经出了它的作用域。

全局变量的作用域是整个工程,即在一个工程文件下即使在多个.c文件内都可以使用。

生命周期:变量的创建到变量的销毁之间的一个时间段

就如上文所提到的i,{ int i }进入代码块i被创建,出代码块i被销毁

生命周期和作用域在表现效果的时候有重叠的现象,但一个是空间一个是时间。不理解也没必要深究

在上文作用域和生命周期的介绍中已经体现全局部变量的区别,现在看实际代码加深理解

​​

全局变量跨文件使用只要声明一下就可以了 

顺便谈谈声明与定义的区别:声明的关键字extern

定义就好比两个人确定男女朋友关系,只能定义一次,总不能两个人好着但又确定男女朋友关系吧🤔。所以代码里不能出现两次的   int  xxx=xxx;

声明就好比你高兴的和室友说你有女朋友了,只要室友不打死你,你说多少次都可以,可以多次声明🤣

区别二:全局变量开辟在内存上的静态区;局部变量开辟在内存上的栈区。(不深究,以后会讲)

问题二: 全局变量和局部变量重名问题

****大家看以下这段代码,判断输出结果

#include<stdio.h>
int g_val=10;
int main()
{
    int g_val=100;
    printf("%d\n",g_val);
    return 0;
}

当全局变量和局部变量重名时,遵循“局部变量优先”原则。所以打印的结果为100 


 二、常量⭐

知识点一:什么是常量🌵

顾名思义,常量就是固定不变的量,一旦被初始化后便不可以被修改。

问题一:以下行为算是修改吗?(const 修饰表示这个数为常变量)

int main()
{
	const int a = 10;
	return 0;
}

 答:初始化不算修改。初始化之后便不可以被修改,不信去试试。

知识点二:有哪些类型的常量🌕

①字面常量🌲

很简单,就是如10,20,‘a’,‘b’;

②常变量:const🌳

const为关键字,说明这个类型的数据为“只读变量”。被const修饰的变量具有某种常属性——即只可以被读取,但是不可以被修改。然而他本质上还是个变量,只不过具有常属性。我们以下面的例子说明。

上面有我们没提到的数组,也顺便讲一下吧。其实很简单,数组就像一个连续货架,他们在内存上开辟的空间连续。这里的int表示数组存储的数据类型为int ,【】表示这个数组有多大,这里为10,说明可以存放十个整形。整形的赋值要用{},赋值为{0}表示将数组里十个元素都赋值为0。这里不细讲,可以看看别人的博文     点这里前往——数组

这里想表达的是,【】内必须是一个常量,而a即使别const定义了还是不能用,说明他本质还是变量

补充一:

在C99语法中支持变长数组这一概念,即【】内可以是变量。但在VS2019 c语言中不支持,且这种方式也不大流行。如果你【】内放入的是变量但是却没有报错,看看自己文件后缀是.c还是.cpp,cpp表示的是c++文件,在c++中是允许的,这点在主线①中有指出过。

③#define定义变量🌴

define定义的就是一个真常量了 ,不行你看 ,以下代码没有任何问题。博主的注释也可以看看,刚写也掉进坑了

#define MAX 10 //没有“=”注意! ,没有;
int main()
{
	int arr1[10] = { 0 };
	int arr2[MAX] = {0};
	return 0;
}

建议一:

#define定义的变量最好名字为大写 

 ④枚举常量🌾

有些事物是可以一一列举的比如性别,我们可以创建一个枚举变量,使用的时候引用就行。

注意中间使用逗号分隔的,不是分号

int main()
{
	enum SEX   //创建枚举常量
	{
		MALE,
		FEMALE,
		SECRET
	};
	enum SEX man = MALE;//使用枚举常量创建变量
	return 0;
}

创建的变量都是有值得我们可以打印一下

 这个值也是可以改变的,但他们还是按顺序增长的


三、字符串⭐⭐

知识点一:字符串怎么存🌵

我们学过字符类型,那该怎么储存字符串类型呢?是不是在C语言里也有字符串对应的类型吗。我只能遗憾的告诉你,在C语言里并没有字符串类型,那我们该怎么存放字符串呢?

字符串储存在数组中,用“”引起来(注意区别:字符是用''引起来的)。我们现在演示一下

int main()
{
	char str[] = "abcd";//数组不指定元素个数则根据后面元素的个数确定
	return 0;
}

我们从上面可可以看到字符串的本质是一个数组,里面一次存入各个字符

‘a’    ‘b’    ‘c’    ‘d’    ‘\0’

\0是什么?明明没有啊。别急,你现在只需记住,凡是字符串在末尾都会自带一个\0

知识点二:\0是什么?有什么用 ?⭐⭐⭐

是什么:\0的ASCLL码值为10,他标志着字符串的结束。

有什么用:就如是什么中提到的,他标志着字符串的结束。没有\0就无法判断一个字符串是否结束。比如strlen和printf以%s的格式打印时就是一直运行直到到达\0停止

我们现在用sizeof和函数strlen(库函数,作用是返回一个字符串的长度。尝试用博主上文提到的方法自主学习,不会欢迎向作者提问) 来验证\0的存在

 size为什么会比strlen长呢?这从侧面说明了\0的存在,要额外占用一字节的空间,而strlen本质上是计算出\0前的字符数。

什么你还不信,那就给你看看内存里到底存的是什么。首先要ctrl+fn+f10(或者ctrl+f10)进入调试状态,敲黑板,一定要进调试状态,不然看不到。 

 怎么样,信了吧。

那来看看一下的几个问题:

问题一:下面打印的结果是

#include <string.h>//库函数要引用头文件
#include <stdio.h>
int main()
{
	char str[6] = "abcdef";
	printf("%s",str);

	return 0;
}

 这是什么鬼东西?别急我们仔细观察下,我们在创建数组是指定了数组的长度为6,也就是说\0放不进去了,所以打印字符串就不知道什么时候会停下来,直到它幸运的在后面遇到一个\0,因此会多很多奇怪的东西。

问题二:下面打印的结果是什么

#include <string.h>//库函数要引用头文件
#include <stdio.h>
int main()
{
	char str[] = {'a','b','c','d','e','f'};
	printf("%s", str);

	return 0;
}

 这又是什么鬼结果?明明字符串大小已经可以自动调节了,可结果怎么还是这么奇怪。来我们分析一下。我们将六个字符存入字符串,这时\0没有被加入,为什么?因为你没写啊。而“abcdef”里的\0是字符串类型自带的,可这里只是把字符放进去,怎么改呢?既然不自动加\0我们就自己加嘛!

 问题三:下面打印的结果是什么

#include <string.h>//库函数要引用头文件
#include <stdio.h>
int main()
{
	char str[7] = {'a','b','c','d','e','f'};
	printf("%s", str);

	return 0;
}

 咦,为什么这样就可以了。因为字符类型的数组,空间有多,自动存入\0。现在我们验证一下


四、转义字符⭐

知识点一:什么是转移字符🌵

我们现在猜测一下下面的结果是什么

#include<stdio.h>
int main()
{
	printf("c:\test\test.c");
	return 0;
}

来揭晓答案

 为什么会这样呢?其实就是转义字符在作怪。那到底什么是转义字符

是什么:''+某个特定字符表示特定的意思(注意转义字符是C语言规定的,不能自行设置)。我们之前就见过\n,他表示换行符。

转义字符意义ASCII码值(十进制)
\a响铃(BEL)007
\b退格(BS) ,将当前位置移到前一列008
\f换页(FF),将当前位置移到下页开头012
\n换行(LF) ,将当前位置移到下一行开头010
\r回车(CR) ,将当前位置移到本行开头013
\t水平制表(HT) (跳到下一个TAB位置)009
\v垂直制表(VT)011
\代表一个反斜线字符'''092
'代表一个单引号(撇号)字符039
"代表一个双引号字符034
?代表一个问号063
\0空字符(NUL)000
\ddd1到3位八进制数所代表的任意字符三位八进制
\xhh十六进制所代表的任意字符十六进制

 现在我们来演示一下。结果大家实际操作一下。

#include<stdio.h>
int main()
{
	printf("abc\b\n");//b相当于backspace
	printf("abc\rd\n");//r相当于用鼠标将光标移到开始位置,也就是a,此时我们在这里输入d
	printf("abc\tdef\n");//t相当于table,水平制表符
	printf("\n\n");//就是想要输出\n而不要理解成换行符,就把\给转义
	printf(""\n");//不加,则第一个“会和第二个”自动组合,第三就会显示不匹配的问题
	printf("\110\n");//1到3个小于8的数字,理解为八进制数字。对照ASCLL码表转化为字符输出
	printf("\x61\n");//x加上任意个小于16的数字表示16进制

}

笔试题⭐⭐

#include<stdio.h>
int main()
{
	printf("%d\n", strlen("c:\test\628\test.c"));
	return 0;
}

答案:14

分析:1.一个转义字符虽然由多个符号组成,但计算字符个数时,当成一个

            2.\628虽然有三个数字,但8不可能是8进制的数字,所以自动忽略

              再比如\6687则这里的转义字符为\66,后面不算

c  :\t  e  s  t  \62  8  \t  e  s  t  .  c                              一共14个