当前位置: 首页 > news >正文

C语言 ——— 认识C语言

目录

认识 main 函数

全局变量和局部变量

extern 关键字

常量

字面常量

const 修饰的常变量

#define 定义的标识符常量

枚举常量

'\0' 是字符串结束标志

%s 打印字符串

strlen 函数

转移字符 \ddd 和 \xdd

转移字符 \ddd

转移字符 \xdd

测试题 

选择语句

单分支选择语句

多分支选择语句

循环语句

while 循环语句

for 循环语句

do while 循环语句

break 关键字和 continue 关键字

break 关键字

continue 关键字

scanf 函数的返回值

牛刀小试

oj题 - 判断一个整数是否能被5整除 

oj题 - 计算 y 的值

oj题 - 时间转换

oj题 - 三角形判断

static 关键字

static 修饰局部变量

static 修饰全局变量

static 修饰函数

认识指针

理解指针

实际例子

指针变量的大小


认识 main 函数

main 函数是程序的入口,程序执行时会从 main 函数的第一行开始执行,且一个工程中 main 函数有且只有一个

标准的 main 函数格式:

int main()
{

	return 0;
}

int 是类型,这里指的是 main 函数的返回类型

return 是返回的意思,通常 main 函数返回 0,表示正常结束程序

古老的 main 函数格式:

void main()
{

}

这是比较古老的 main 函数格式,void 表示没有返回值,不用 return 返回

如果书籍或者教材中有这种 main 函数的写法,大概率可以不用看了

不接受参数的 main 函数格式:

int main(void)
{

	return 0;
}

main 函数括号中的 void 表示这个 main 函数不接受任何参数


sizeof 操作符

sizeof 操作符的作用是计算 类型/变量 所占内存空间的大小,单位是字节(byte)

sizeof 计算内置类型所占空间的大小:

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

	return 0;
}

%d 的意思是以 10 进制的形式打印一个整数,因为 sizeof 关键字的返回类型是整形,所以使用 %d 的形式打印

运行代码:

可以看到 char 类型所占内存空间大小为 1 字节、short 类型所占空间大小为 2 字节...

因为 C语言 规定,只要 sizeof(long) >= sizeof(int) 即可,所以 sizeof(long) 的大小是 4 字节,在有些平台下 sizeof(long) 的大小是 8 字节


全局变量和局部变量

代码演示:

int b = 100;

int main()
{
	int a = 10;

	return 0;
}

定义在 main 函数内部的变量 a 就是局部变量

定义在 main 函数外部的变量 b 就是全局变量

生命周期:

变量 a 的生命周期是在 main 函数内部,当 mian 函数执行完了 return 后,变量 a 的生命周期就结束了

变量 b 的生命周期是整个工程结束时,变量 b 的生命周期才结束

当全局变量的变量名和局部变量的变量名冲突时:

int a = 100;

int main()
{
	int a = 10;

	return 0;
}

通过 printf 函数测试代码是否能正常执行,并且测试出有限执行的哪个变量

测试代码:

可以看到,优先执行了局部的变量 a

小结:

首先原则上变量名尽量不要冲突,但是当全局变量和局部变量的名字冲突的情况下,局部变量优先


extern 关键字

extern 关键字的作用是声明外部符号

例如:

有两个 .c 文件,分别为 add.c 文件和 test.c 文件

add.c 文件的代码:

int a = 2025;

那么想要在 test.c 文件中使用 add.c 文件中的变量 a,就需要使用 extern 关键字

test.c 文件使用变量 a:

extern int a;

int main()
{
	printf("a = %d\n", a);

	return 0;
}

要想使用 add.c 文件中的变量 a,要先在 test.c 文件中对变量 a 进行声明,才能正常使用

运行 test.c 文件:


常量

字面常量

字面常量顾名思义就是字面意义的常量,不能改变的量就叫常量

比如:圆周率、由 0-9 组成的数字、字符、字符串... 

const 修饰的常变量

代码演示:

const int a = 10;

定义了一个 int 类型的变量 a,并且这个变量 a 被 const 修饰了,此时 a 就具有了常属性

也就表示 a 的值不能被改变了,只能在初始化的时候赋值

且 a 本质还是一个变量,因为不能给数组定义长度,只是 a 这个变量不能被修改,所以称 a 为常变量

#define 定义的标识符常量

代码演示:

#define SIZE 10

这个代码可以理解为给 10 这个常量取了一个名字叫 SIZE,此时的 SIZE 就是标识符常量

那么 SIZE 就能给其他同类型的变量赋值,且可以给数组定义长度

在执行代码时,程序会把有 SIZE 的地方全部替换为常量 10

枚举常量

枚举常量顾名思义是能被一一列举的常量,比如:性别、三原色、血型等

代码演示:

enum COLOR
{
	Red,
	Green,
	Blue
};

enum 是定义枚举常量的关键字,COLOR 是枚举常量的结构体名称

其中 Red、Green、Blue 是枚举出的三原色,他们都有各自的默认值,Red 是 0,后面的依次递增

代码测试:

可以在初始化的时候重新给他们赋值,并且还是遵循依次递增的规定


'\0' 是字符串结束标志

'\0' 是表示字符串结束的标志,不论是用 %s 打印字符串,还是用 strlen 函数求字符串长度,都是遇到 '\0' 才结束,否则就会一直执行,知道遇到 '\0' 才停止

%s 打印字符串

%s 表示的是打印一串字符,一般和 printf 函数配合使用

代码演示:

char arr1[] = { 'a','b','c','d' };
char arr2[] = "abcd";

在数组 arr1 中存储了 4 个字符,但在数组 arr2 中不只是存储了 "abcd" 字符串,在 "abcd" 字符串末尾还存放了一个 '\0'

可以通过监视验证:

那么以 %s 分别打印两个数组时,arr1 数组就会除了打印字符还会打印其他未定义字符,直到遇到 '\0' 才会停止

代码验证:

strlen 函数

strlen 函数的作用是求字符串长度,所需要的头文件为 #include<string.h>

且 strlen 函数同样是求到 '\0' 之前的长度,当没有 '\0' 的话就会一直求长度,直到遇到 '\0' 为止

代码验证:

因为不知道数组 arr1 何时遇到 '\0' ,所以是随机值

解决办法:

可以在 arr1 数组中手动加上 '\0'

代码演示:

char arr1[] = { 'a','b','c','d','\0' };

 这样不论是 %s 打印还是 strlen 求长度,都能正常输出结果


转移字符 \ddd 和 \xdd

转移字符 \ddd

其中 ddd 表示 1~3 个八进制的数字

代码演示:

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

%d 是以十进制的方式打印,那么 130 这个八进制数字转换为十进制为 88 

因为 130 各自的权重相乘在相加为 0*8^0 + 3*8^1 + 1*8^2 = 88

代码验证:

那么以 %c 字符形式打印,那么结果就会变成大写的 X,因为 88 所对应的 ASCII 码值就是 X

代码验证:

转移字符 \xdd

x 表示是十六进制的数字,其中 dd 表示 2 个十六进制的数字

代码演示:

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

十六进制的 61 转换为 十进制为:1*16^0 + 6*16^1 = 97

代码验证:

那么同样的道理,以 %c 的形式打印的话也就是打印 97 所对应的 ASCII 码值

代码验证:

测试题 

代码演示:

printf("%d\n", strlen("C:\test\127\x56\test.c"));

问:strlen 求出的长度是多少

易错点:其中 '\t'  '\127'  '\x56' 是转移字符,本质只占用1个字节

所以统计后的结果应该是 14 字节

代码验证:


选择语句

单分支选择语句

代码演示:

int a = 0;

if (a == 0)
{
	printf("a == 0\n");
}
else
{
	printf("a != 0\n");
}

当满足 if 语句中的条件判断时,就不会执行 else 语句,否则就相反

所以代码中只会执行 if 语句内的代码 

多分支选择语句

代码演示:

int a = 0;

if (a > 0)
{
	printf("a > 0\n");
}
else if (a < 0)
{
	printf("a < 0\n");
}
else
{
	printf("a == 0\n");
}

既不满足 if 语句的条件,也不满足 else if 语句的条件,所以最后会打印 else 语句中的代码 


循环语句

循环语句顾名思义就是循环执行循环内部的代码,直到满足特定的条件才会跳出循环 

while 循环语句

代码演示:

int a = 0;

while (a < 5)
{
	printf("a = %d\n", a);

	a++;
}

满足条件,进入 while 循环,进入 while 循环时,先打印,变量 a 再自增 1 ,最后直到 a 不小于 5 时就循环结束

代码验证:

for 循环语句

代码演示:

for (int a = 0;a < 5;a++)
{
	printf("a = %d\n", a);
}

for(表达式1; 表达式2; 表达式3) 执行逻辑是:

先执行 表达式1,再判断 表达式2 是否满足条件,满足条件时进入 for 循环内部,执行完内部的代码后再回到 表达式3并且执行,执行完 表达式3 后再判断是否满足 表达式2 ,满足就再次进入循环(循环往复),不满足就跳出循环

代码验证:

do while 循环语句

代码演示:

int a = 0;

do
{
	printf("a = %d\n", a);
	a++;

} while (a < 5);

do while 循环语句的特点是:不论是否满足进入循环的条件,都会先进入循环内部执行一次代码,执行完之后再判断是否满足条件,满足就继续执行,不满足就跳出循环

代码验证:

break 关键字和 continue 关键字

break 关键字

break 关键字的作用是结束并且跳出当前循环

代码演示:

for (int a = 0;a < 5;a++)
{
	printf("a = %d\n", a);

	if (a == 3)
	{
		break;
	}
}

当 a 等于 3 时就会执行 break,跳出循环

代码验证:

需要注意的是 break 只能跳出当前循环,如果是双重循环或者多重循环时,只能跳出 break 所在的那层循环

代码演示:

for (int i = 0;i < 1;i++)
{
	for (int a = 0;a < 5;a++)
	{
		printf("a = %d\n", a);

		if (a == 3)
		{
			break;
		}
	}

	printf("i = %d\n", i);
}

当内部循环走到 break 跳出时,外部的循环依然要执行

代码验证:

continue 关键字

continue 关键字的作用是跳过循环内部 continue 下面的代码,从头执行循环(当然要判断是否满足循环条件,满足再继续执行,否则就结束循环)

代码演示:

for (int a = 0; a < 5; a++)
{
	if (a == 3)
		continue;

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

当变量 a 等于 3 时就执行 continue,跳过后面的 printf 函数,重新执行循环

代码验证:

小结

break 和 continue 关键字只能在循环内部使用,否则就会报错 


scanf 函数的返回值

scanf 函数的功能可以从键盘上读取数据,并且存储到对应的变量中

而 scanf 函数的返回值是读取数据的个数

代码演示:

int a = 0;
int b = 0;

int ret1 = scanf("%d", &a);
printf("ret1 = %d\n", ret1);

int ret2 = scanf("%d %d", &a, &b);
printf("ret2 = %d\n", ret2);

第一个 scanf 函数只从键盘接收一个数据,并且用 ret1 接收 scanf 函数的返回值

第二个 scanf 函数从键盘接收了两个数据,分别打印 两个 scanf 函数的返回值,看是否分别是 1 和 2

代码验证:

注意:

当 scanf 函数没有正常接收数据时,会返回 EOF(文件结束标志),可以通过让 scanf 函数接收 Ctrl+Z 键,就能返回 EOF  


牛刀小试

oj题 - 判断一个整数是否能被5整除 

题目描述:

输入一个正整数,判断这个数是否能被 5 整除,要求能多次输入输出

代码实现:

int input = 0;

while (scanf("%d", &input))
{
	if (input % 5 == 0)
	{
		printf("%d能被5整除\n", input);
	}
	else
	{
		printf("%d不能被5整除\n", input);
	}
}

代码解析:

直接利用 scanf 函数的返回值作为 while 循环的判断语句,只要正常接收了数据,就会进入循环

并且用 % 取模操作符进行判断,当 input%5 的余数为 0 时,就是能被 5 整除,否则就不能

代码验证:

oj题 - 计算 y 的值

题目描述:

已知一个函数 y=f(x),当 x>0 时, y=1,当 x=0 时,y=0,当 x<0 时,y=-1

要求输入 x,求出对应的 y

代码演示:

int x = 0;
int y = 0;
scanf("%d", &x);

if (x > 0)
	y = 1;
else if (x < 0)
	y = -1;
else
	y = 0;

printf("y = %d", y);

oj题 - 时间转换

题目描述:

给定秒数 seconds,把秒转换为小时、分钟、秒,并且分别输出

代码演示:

int seconds = 0;
scanf("%d", &seconds);

int h = seconds / 3600;
int m = (seconds % 3600) / 60;
int s = seconds % 60;

printf("%d秒 = %d小时%d分钟%d秒", seconds, h, m, s);

代码解析:

1 小时为 3600 秒,所以 seconds 除以 3600 秒就能计算出有多少个小时

seconds 取模上 3600 秒就能计算出不足一小时的有多少秒,再除以 60 秒,就能计算出还有多少分钟

seconds 直接取模上 60 秒,就能计算出不足以 60 秒的有多少秒

代码验证:

oj题 - 三角形判断

题目描述:

输入三角形的 3 条边 a、b、c,判断是否能构成三角形,如果不能构成三角形直接输出"Not a triangle!",如果能构成三角形则判断这个是什么三角形,如果是等边三角形则输出"Equilateral triangle!",如果是等腰三角形则输出"Isosceles triangle!",如果是普通三角形则输出"Ordinary triangle!",并且要求能多组输入输出

代码演示:

int main()
{
	int a = 0;
	int b = 0;
	int c = 0;
	
	while(scanf("%d %d %d", &a, &b, &c) == 3)
	{
		
		if (a + b > c && a + c > b && b + c > a) //先判断是否能构成三角形:任意两边之和不能大于第三边
		{
			if (a == b && b == c) //等边三角形三条边都相等
			{
				printf("Equilateral triangle!\n");
			}
			else if ((a == b && a != c) || (a == c && a != b) || (b == c && b != a)) //等腰三角形任意两边相等
			{
				printf("Isosceles triangle!\n");
			}
			else //普通三角形
			{
				printf("Ordinary triangle!\n");
			}
		}
		else
		{
			printf("Not a triangle!\n");
		}
	}

	return 0;
}

代码验证:


static 关键字

static 修饰局部变量

被 static 修饰的局部变量称之为静态局部变量

代码演示:

void test()
{
	static int a = 5;
	a++;
	printf("%d ", a);
}

int main()
{
	for (int i = 0; i < 10; i++)
	{
		test();
	}

	printf("\n");

	return 0;
}

对 test 函数内部定义的局部变量 a 进行了 static 修饰,此时的 a 就是静态局部变量

如果忽略 static 修饰的话,那么程序运行的结果就是 10 个 5,但是加上了 static 修饰,结果就会不同

代码验证:

可以看到,并没有每次进入 test 函数时都重新给变量 a 初始化,而是延续了上次递增的值

原因是因为变量 a 所存储的区域被 static 改变了,从栈区转换到了静态区

在 C语言 学习的时候,可以把内存大概划分为栈区、堆区、静态区

示意图:

所以 static 修饰局部变量改变了变量的存储位置,使得这个静态变量的生命周期延长了,直到程序结束时这个变量的生命周期才结束

static 修饰全局变量

被 static 修饰的全局变量称之为静全局部变量

add.c 文件代码演示:

static int val = 2025;

test.c 文件代码演示: 

extern int val;

int main()
{
	printf("%d", val);

	return 0;
}

在 add.c 文件中定义了一个全局变量,并且在 test.c 文件中用 extern 关键字声明了 val 变量

如果忽略 static 关键字的话,在 test.c 中能够正常运行代码,因为任何一个全局变量都具有外部链接属性

但是全局变量 val 被 static 修饰后,val 变量就没有了外部链接属性,static 把 val 变量的外部链接属性转换为了内部链接属性,所以 val 变量只能在它所处的 add.c 文件内部使用 

static 修饰函数

被 static 修饰的函数称之为静态函数,被修饰后的作用和 static 修饰全局变量后的作用相似

add.c 代码演示:

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

test.c 代码演示:

extern int Add(int x, int y);

int main()
{
	printf("%d\n", Add(5, 3));

	return 0;
}

Add 函数被 static 修饰后,同样把 Add 函数的外部链接属性转换为了内部链接属性

并且 Add 函数只能在 add.c 文件内部使用,其他任何 .c 文件都不能使用了


认识指针

指针是来管理内存的,通常使用指针来存放变量的地址

理解指针

代码演示:

int a = 10;

int* pa = &a;

& 操作符的作用于取地址,&a 就是取出变量 a 的地址

pa 的类型是 int* ,* 的意思是表明 pa 是指针变量,用来存放指针的,int 的意思是表明所要存放地址的数据类型

当变量 a 的地址存放到了 pa 中后,就可以利用 * 解引用来操作变量 a

代码演示:

*pa = 100;

*pa 可以理解为通过 pa 所存放的地址找到变量 a,再对 a 重新赋值

代码验证:

实际例子

写一个函数,交换两个整数的值

代码演示:

void swap(int* x, int* y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}
int main()
{
	int a = 3;
	int b = 5;

	swap(&a, &b);

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

	return 0;
}

因为形参和实参是各自独立的空间,所以只有把 a 和 b 的地址传递给 swap 函数,才能改变 a 和 b 的值

代码验证:

指针变量的大小

因为指针是用来存放地址的,所以不论是什么类型的指针,在不同的平台下都是固定的

在 32 位平台下:

在 64 位平台下:

相关文章:

  • 应对海量数据归档难题?AWS Glacier 的低成本冷存储解决方案实践指南
  • Keras使用1
  • 【AI学习从零至壹】语⾔模型及词向量相关知识
  • linux多线(进)程编程——(6)共享内存
  • 链表代码实现(C++)
  • C语言--常见的编程示例
  • 医药采购系统平台第5天01:药品目录导入功能的实现Oracle触发器的定义供货商药品目录模块的分析供货商目录表和供货商控制表的分析、数据模型设计和优化
  • Rasa 模拟实现超简易医生助手(适合初学练手)
  • Tkinter表格与列表框应用
  • 制作像素风《饥荒》类游戏的整体蓝图和流程
  • ubuntu 2404 安装 vcs 2018
  • Doris 安装部署、实际应用及优化实践:对比 ClickHouse 的深度解析
  • 从零搭建高可用Kafka集群与EFAK监控平台:全流程实战总结
  • Foxmail邮件客户端跨站脚本攻击漏洞(CNVD-2025-06036)技术分析
  • Go:基本数据
  • leetcode 139. Word Break
  • < 自用文 Project-30.6 Crawl4AI > 为AI模型优化的网络爬虫工具 帮助收集和处理网络数据的工具
  • Java中的数组
  • 苍穹外卖Day-5
  • c# 新建不重名的唯一文件夹
  • 五一去哪儿| 追着花期去旅行,“赏花经济”绽放文旅新活力
  • 屠呦呦当选美国国家科学院外籍院士
  • 徐徕任上海浦东新区副区长
  • “ChatGPT严选”横空出世了,“DeepSeek严选”还要等多久?
  • 中国防疫队深入缅甸安置点开展灾后卫生防疫工作
  • 建行一季度净利833.51亿同比下降3.99%,营收降5.4%