C语言初窥门径

C语言初窥门径

如标题所言,以下内容都是简单介绍一下,在以后的新文章中将会进行深入说明。这篇文章会让你对C语言在大体上有一个初步的认识

1.C语言简介

如果大家有兴趣的话可以去搜一下TIOBE,这是一个编程语言排行的榜单,我下面的两张图片就来自于这个榜单

C语言初窥门径_第1张图片

上面是2023年十月份的榜单,C语言在该榜单中排行第二,同样可以看到第二列2022年排行中C语言也是位列第二,足以看到C语言的强大。有些同学看到这里就会问了,哎,那我看这Python还是第一呢,怎么不见你说Python呢。有些同学对于先学Python还是先学C语言二者之间很难抉择,我的建议是先学C语言,因为C语言中有个极其难理解的东西叫做指针,一旦搞懂了指针,你就会“哦原来是这样,C语言也没那么难嘛”,此时再去学习Python就跟洒洒水一样。但是,如果你先学Python,也会发现Python不难,但是之后再学C语言就会让你极其痛苦。再来看一个图片:

C语言初窥门径_第2张图片

这是二十年来,编程语言的折线图,蓝紫色表示的是C语言,不难看出C语言一直位列前三,甚至可以说前二。在成百上千种编程语言中常年占据前三,足以说明一些问题。

C 语言是一种通用的高级语言,最初是由丹尼斯·里奇在贝尔实验室为开发 UNIX 操作系统而设计的。C 语言最开始是于 1972 年在 DEC PDP-11 计算机上被首次实现。在 1978 年,布莱恩·柯林汉(Brian Kernighan)和丹尼斯·里奇(Dennis Ritchie)制作了 C 的第一个公开可用的描述,现在被称为 K&R 标准。UNIX 操作系统,C编译器,和几乎所有的 UNIX 应用程序都是用 C 语言编写的。由于各种原因,C 语言现在已经成为一种广泛使用的专业语言。

C语言初窥门径_第3张图片

这本书就是这两人写的,但是我建议初学者看《C Primer Plus》或者《C语言程序设计现代方法》

C语言初窥门径_第4张图片

C语言初窥门径_第5张图片

就简单说到这里,下面开始进行C语言正式的讲解,这篇文章也只是对C语言的整体有个初步的认识,每个知识都浅谈一下,在以后的新文章中将会进行深入的说明。

2.变量与常量

这里我直接从变量开始说起,就不对数据类型这些非常简单的东西作以介绍了。

变量

变量变量,顾名思义就是可以变化的量,如你的年龄会随着时间的变化而增加,你的年龄就是一个变量。

变量命名,也非常容易理解,就是给一个变量起一个名字。可以是a,b,c,d,又或者是age,time等等。

对于变量命名这里面有几个规则,硬性规则是变量命名只能由数字、字母、下划线组成,并且不能以数字开头,很好理解吧。举几个例子

int age = 18; //纯字母组成
int age_ = 18; //字母和下划线组成
int _age = 18; //下划线在前,字母在后也是可以的
int age_5 = 18; //字母,下划线和数字组成,也是可以的
int 5_age = 18; //也是数字、字母和下划线组成,但是不能将数字放在开头,这是一个错误示范

其次,建议同学们再给变量命名的时候,尽量让变量名有意义,比如我上面的命名,我可以写age,也可以写a,b这样没有意义的名字,在语法上没有任何问题,但是可读性就差了不少,同学们想一想,以后去到公司,那肯定是大量的代码啊,你给变量起个a这样的名字,谁能知道你这表示的是什么意思,使得代码的维护更加艰难,但是你起个age,人一看就明白这表示的是年龄,起一个有意义的名字是一个很好的编程习惯。

还有就是变量名不能冲突,也就是不要起相同的名字,当全局变量和局部变量冲突时,局部变量优先。举个例子

#include 

int a = 5; //这里是全局变量

int main()
{
	int a = 10; //这里是局部变量
	printf("%d\n", a); 

	return 0;
}

这里的结果会是10,这就是局部变量优先。

变量的作用域和生命周期
作用域

简单说,这个变量在哪段代码当中起作用,代码范围就是变量的额作用域。

局部变量的作用域就是局部变量所在的局部范围。

全局变量的作用域是整个工程。

生命周期

人的生命周期就是从出生到死亡,变量的生命周期就是从变量的创建到销毁。

局部变量的生命周期是从进作用域开始,到出作用域结束。

全局变量的生命周期就是整个程序的生命周期。

常量

常量相信同学们也都理解,就是不变的量,比如你的身份证号,一般称为字面常量。这里还有三个重点介绍的。

const修饰的常变量

第一个是const修饰的常变量。有同学就问了,常量就常量,变量就是变量,常变量是个什么东西啊?简单说就是具有常属性的变量。举个例子

#include

int main()
{
	int age = 18;
	age = 20;
	printf("%d\n", age);

	//const int score = 90;
	//score = 100;  //这里的score是不能直接修改的
	//printf("%d\n", score);

	return 0;
}

上述代码age就是正儿八经的变量,先定义了age为18,后面再改变age为20,运行结果就是20;如果你把注释的代码添加进去,你会发现编译不过,就是因为使用const修饰的score具有了常属性,编译器认为他是个常数,就不能改变了,所以后续将它改为100,编译器通过不了,但是它本质上还是变量,只是从语法层面上让该变量不能被改变。打个不恰当的比方,就像一个俊美的男生穿了长裙,在别人看来他是一个女生,但实际上他还是个男生,const就相当于是长裙。

#define定义的标识符常量

直接上代码

#include

#define PI 3.14 //这里就是定义的标识符常量
int main()
{
	printf("%f\n", PI);

	return 0;
}

用#define定义的标识符常量有什么优势呢?就拿π来举例,如果代码长达几百上千行,在程序中你可能会使用几次、十几次甚至几十次的π,这时候的π是3.14,但是有一天你发现3.14这个精度低了,想要将所有的π都改成3.14159,难不成要在程序中将十几个π,一个一个找出来改成3.14159?这不现实,那怎么弄?用#define定义,后续想要改动,只需要将#define后面的3.14改成3.14159,在这个程序下的所有π的值都会改为3.14159,是不是省事很多呢

枚举常量 enum

直接上代码

#include
//枚举
enum DAY 
{
	MORNING = 1,
	AFTERNOON = 2,
	EVENING = 3,
}day;

int main()
{
	enum DAY day;
	day = MORNING;
	printf("%d\n", day);

	return 0;
}

括号里的MORNING,AFTERNOON,EVENING就是枚举常量,如果不赋值,枚举常量默认从0开始,向下依次递增1。这里就是简单看一下就可以了,后面会深入介绍的

3.字符串

字符串有一个很重要的点,那就是结束的标志是 \0,只有遇到了 \0 才会结束。举个例子

#include
#include //头文件,包含了strlen函数
int main()
{
	char ch[] = { 'a', 'b', 'c'}; //字符
	char ch2[] = { "abc" }; //字符串
	printf("%d\n", strlen(ch));
	printf("%d\n", strlen(ch2));
	//strlen函数是求字符串长度的,从给定的地址向后数字符,直到遇见\0结束,\0不统计在内

	return 0;
}

我们来看一下运行结果

在这里插入图片描述

这不对劲啊,这同样都是abc三个字符啊,我能理解下面的长度是3,为什么上面的一行的输出结果是19呢?上面说过,\0 是字符串结束的标志,在双引号里的abc属于字符串,隐含着\0,可以理解为在双引号的后引号前隐藏了一个\0,只是没有显示出来,而在第一行中的a,b,c并不是正经的字符串,而是三个字符,想要计算第一行的长度需要手动输入 \0

char ch[] = {'a', 'b', 'c', '\0'}

此时再运行结果就会是3

在这里插入图片描述

C语言初窥门径_第6张图片

看图,对于第二行来说,长度会从1号箭头指的a的地址往后数,到\0就是2号箭头所指的地址,此时是三个字符,返回3。对于第一行来说编译器会从1号箭头指的a所在的地址往后数,直到数到\0才会返回一个值,而\0可能会在3号箭头所指的位置,也可能会在2号箭头所指地址后面的任意一个位置,这时候返回值一定是一个大于等于3的随机值,在我的电脑上显示19,在你的电脑上可能就是8或者40或者16等随机值。

4.转义字符

这里介绍几个常见的转义字符和两个较难的转义字符

\’

让单引号不被解析为一对单引号中的单引号

\"

让双引号不被解析为一对双引号中的双引号

比如你想要打印一个双引号,你打算这样写代码

#include

int main()
{
	printf("""); 

	return 0;
}

你会发现编译器报错,这个时候你给要打印的双引号前加一个\,再次运行就会打印出 "

C语言初窥门径_第7张图片

\\

双斜杠是让后面的斜杠不要被解析为转义字符里面的斜杠,多在表示路径时使用。

比如路径D:\Code\c_language在打印是不能直接写成这样

printf("D:\Code\c_language");

在这里插入图片描述

你会发现打印结果中斜杠没有打印出来,这个时候就需要使用双斜杠

printf("D:\\Code\\c_language");

在这里插入图片描述

这个时候再打印你会发现完整的路径被打印出来了。

\a

这是一个警告字符,你可以试着打印一个\a,运行程序,你会听到你的电脑响了一下。

\b

\b叫做退格符,\b出现的时候会往前退一格。

printf("123\b456");

C语言初窥门径_第8张图片

运行一下你会发现3没了,这就是退格符\b的作用,会让4往前退一格,将3覆盖掉了,所以结果没有3。

\n

\n应该是同学们最常用的一个转义字符了,功能是换行,相当于键盘上的回车键,只不过回车键是输入设备的换行,\n则是在输出设备上让打印结果换行。

\t

\t叫做水平制表符,可以尝试动手写一下,一般是左对齐总共时8个算一个,但是可以设置。

\ddd

\ddd和\xdd是最难理解的两个转义字符了,先来说说\ddd。

\ddd 中的d d d 表示1到3个八进制的数字。也就是1到3个0~7的数字,比如

printf("\101");

C语言初窥门径_第9张图片

你发现输出结果是A,这是为什么呢?这是因为101是八进制数,它会先转换为十进制数,再打印出该十进制数所对应的ASCII码值。

\xdd

\xdd 中的d d 表示两个十六进制数,也就是2个09、AF,其余和\ddd无异。

5.注释

注释,也就是给代码做一个简要的文字解释,相当于中学语文课本中文言文和古诗文下面的注解一样,为了让文章更加容易被理解,注释也是让代码更容易被读懂。在C语言中有两种风格的注释。

第一种风格,也被称为C++风格,只能注释单行

//你要注释的内容

第二种风格,是C语言风格,可以注释多行

/* 你要注释
的内容 */

C语言风格的注释有一个缺点,那就是不能嵌套注释。

6.选择语句

C语言中的三大基本结构,有顺序结构,选择结构(也叫分支结构),循环结构。选择语句就是选择结构,主要有if…else和switch两种,后面的新文章将会详细介绍,这里举一个简单的if语句:

#include

int main()
{
	int score = 0;
	printf("请输入你的分数(0-100):");
	scanf("%d", &score);
	
	if (score >= 80)
		printf("优秀\n");
	else 
        printf("继续加油\n");

	return 0;
}

7.循环语句

顾名思义就是重复循环的,一直做,就像我们同学要日复一日的学习。主要有三种,while,for和do…while,也将在后面的新文章中详细介绍。这里简单说一下while语句。

#include

int main()
{
	int book_num = 0;

	while (book_num <= 5)
	{
		book_num++;
		printf("请继续阅读\n");
	}

	if (book_num > 5)
		printf("知识渊博\n");

	return 0;
}

8.函数

一个函数能完成一个独立的功能,简化代码

比如我要实现一个加法的程序,不用函数是这样

#include

int main()
{
	int a = 0;
	int b = 0;
	int sum = 0;

	scanf("%d%d", &a, &b);
	sum = a + b;
	printf("%d\n", sum);

	return 0;
}

如果使用函数,代码则是这样

#include

int Add(int x, int y)
{
	return x + y;
}

int main()
{
	int a = 0;
	int b = 0;
	int sum = 0;

	scanf("%d%d", &a, &b);
	sum = Add(a, b);
	printf("%d\n", sum);

	return 0;
}

有些人说了,这看着也没见简化啥,这是因为这段非常简单,只实现了一个加法的功能。如果一个比较复杂的功能需要上百行代码,这时使用函数是不是就会简化代码。

9.数组

什么叫数组?那就是一组数呗。官方定义:一组相同类型元素的集合。

数组可以通过下标来访问,比如我定义有5个整型元素的数组:

int  arr[5] = {1,2,3,4,5}; // 定义一个放五个元素的整型数组 

我这个数组有5个元素,那么下标的范围就是0~4

int arr[5] 1 2 3 4 5
下标 0 1 2 3 4
#include

int main()
{
	int i = 0;
	int arr[5] = { 1,2,3,4,5 };
	
	printf("%d\n", arr[1]);

	return 0;
}

因为数组的下标从0开始,这个结果就是第二个元素2的值。

10.操作符

这里仍只是认识一下,后面详细介绍。C语言的灵活性就体现在操作符上,可以直接操作到二进制位。

算术操作符

+  -  *  /  %

移位操作符

移动的是二进制位

>>  <<

位操作符

操作的也是二进制位

&  ^  |

赋值操作符

=  +=  -=  *=  /=  |=  >>=  <<= 

单目操作符

单目的意思是只有一个操作数

!       逻辑取反,在C语言中,0为假,非0为真
-       负值
&       取地址   
sizeof  操作数的类型长度
~       对一个数的二进制按位取反
--      有前置和后置之分,前置--为先-后使用;后置--为先使用后-
++      有前置和后置之分,与--相同
*       间接访问操作符(解引用操作符)
(类型)   强制类型转换
   
//sizeof的用法
#include

int main()
{
	printf("%d\n", sizeof(int));
	printf("%d\n", sizeof(char));
	printf("%d\n", sizeof(float));
	printf("%d\n", sizeof(double));
	printf("%d\n", sizeof(long long));
	
	return 0;
}

C语言初窥门径_第10张图片

这就是这五个类型所占内存空间的大小,单位是字节

关系操作符

>  >=  <  <=  !=  ==

逻辑操作符

&&     逻辑与,表示并且
||     逻辑或,表示或者

条件操作符

也叫三目操作符,是C语言中唯一的三目操作符

语句1 ? 语句2 : 语句3

意思为当
语句1为真是则执行语句2,语句3不执行;语句1为假时。语句2不执行,执行语句3

#include

int main()
{
	int a = 5;
	int n = (a = 5) ? 1 : 0;
	printf("%d\n", n);

	return 0;
}

结果为1

逗号操作符

语句1, 语句2, ,语句3

从左往右依次计算,结果是最后一个表达式的结果

#include

int main()
{
	int a = 1;
	int b = 2;
	int c = 3;
	int d = (a+b, a+b, a+b+c*5);

	printf("%d\n", d);

	return 0;
}

虽然这里的结果是18,和前面的a+b没有关系,好像可以直接由最后一个式子算出来,其实并不是这样,要从左往右依次计算,最后的结果是最后一个表达式的结果。

#include

int main()
{
	int a = 0;
	int b = 0;
	int c = 0;
	a = (c=10, b=c%8, b+1);

	printf("%d\n", a);

	return 0;
}

这段代码的结果运行的结果是3,从左往右依次计算c=10,b=2,b+1=3,最后返回3.如果直接算b+1,那答案是1,显然是错误的。

下标引用、函数调用和结构成员

[]  ()  .  ->
[]  数组下标的引用,如arr[1]      
()  函数的调用,如Add(a,b)
后面两个可以用来访问结构体中的结构成员,这里不详细介绍

11.关键字

C语言中总共有32个关键字,这是C语言设定好的,用户不能创造。在这里介绍两个关键字typedef和static

typedef

typedef的作用是对类型的重命名,如无符号长整型是unsigned long long ,在多次使用时比较繁琐,看着也比较冗余,可以这样让写代码更加方便。

#include

typedef unsigned long long ull;
int main()
{
	ull a = 20;
	ull b = 30;
	ull c = 50;

	printf("%d\t%d\t%d", a, b, c);

	return 0;
}

在上述代码中,将unsigned long long重命名为ull,在后续代码的编写中更加方便

static

修饰局部变量

看如下代码

#include

void A()
{
	int i = 0;
	i++;
	printf("%d\n", i);
}

int main()
{
	int i = 0;

	for (i = 0; i < 5; i++)
	{
		A();
	}

	return 0;
}

结果为5个1,这是因为主函数运行到调用函数A时,进入函数A后,创建一个变量i=0,然后i++,使得i变为1,再打印i,结果就是1,然后出了函数A后变量i会被销毁,然后等到循环第二次再次运行到调用函数A,进入函数A后,创建一个变量i=0,然后i++,使得i变为1,再打印i,结果还是1,第三次,第四次,第五次也是这样,所以最终的结果为5个1。

再看使用static修饰过局部变量的程序

#include

void A()
{
	static int i = 0; //static修饰过的局部变量
	i++;
	printf("%d\n", i);
}

int main()
{
	int i = 0;

	for (i = 0; i < 5; i++)
	{
		A();
	}

	return 0;
}

这段代码的结果是1 2 3 4 5 ,这是因为static修饰的局部变量的生命周期被延长了,让该局部变量出了作用域后不被销毁,依然存在,一直到程序结束生命周期才结束。所以在出函数A时,已经创建的变量i不会被销毁,所以在下一次循环调用函数A时会在上一次的基础上进行++操作。

这里就要说到内存了,内存大概可以划分为三个区域,分别为栈区、堆区和静态区。如图

C语言初窥门径_第11张图片
这里所说的变量销毁并不是真正的摧毁毁灭,而是还给操作系统。相当于你租房,不住了退房一样。

static修饰的局部变量就不存在栈区了,而是被存放到静态区,具有静态变量的特点

修饰全局变量

全局变量本身具有外部链接属性,可以在其他源文件内部使用,但被static修饰后,全局变量的链接属性被改变了,由外部变成了内部,只能在自己所在的源文件内部使用,相当于作用域变小了。

C语言初窥门径_第12张图片

我们可以看到这时候是可以打印出外部变量的值的。

C语言初窥门径_第13张图片

这时候我用static修饰以后,发现报错了,说int year是无法解析的外部命令,说明12.cpp中使用不了11.cpp中的外部变量,可以看出外部全局变量被static修饰后失去了本身具有的外部链接属性。

修饰函数

static修饰函数与全局变量是类似的

C语言初窥门径_第14张图片

C语言初窥门径_第15张图片

12.#define 定义标识符常量和宏

前面已经说过#define定义标识符常量了,这里说一下宏定义

#include

#define Add(x, y) (x+y) //宏定义,从左往右 #define 名称(参数) 实现体,有点类似于函数
int main()
{
	int sum = Add(1, 1);
	printf("%d\n", sum);

	sum = 2 * Add(1, 1);
	printf("%d\n", sum);

	return 0;
}

13.结构体

前面说到数组是一组相同类型元素的集合,要么全是整型,要么全是字符。结构体可以描述复杂的类型。比如说来描述学生,学生信息有姓名,性别,年龄等等信息,无法使用相同类型描述,所以这里就只能使用结构体来描述了。

#include

struct Stu
{
	char name[20]; //名字是字符串,一个汉字是两个字符
	int age; 
	char sex[5]; 
};

int main()
{
	struct Stu a = { "小刘", 19, "男" };
	printf("%s %d %s", a.name, a.age, a.sex); //.访问结构成员
	
	return 0;
}

这里的.就是前面说到的访问结构成员的操作符

由于指针较为复杂,哪怕是初步认识也需要很多篇幅来说明,所以我将在下一篇文章中对指针进行一个简单的介绍。

如果您觉得有用,请动动您的指头,点点小赞,点点关注,感谢!!!

你可能感兴趣的:(C语言,c语言,开发语言)