[简明C语言]C语言概述P_3:选择语句/循环语句/函数/数组/操作符/常见关键字


前言

C语言功能强大,使用灵活,既可以用于编写应用软件,又用于编写系统软件。熟练掌握C语言是在计算机科学与技术专业学习中计算机开发人员的一项基本功。本文记录了简明C语言_C语言概述的第三部分内容。


1. 初识选择语句

人生有很多路可以去选择,但只有一条路不能选择,那就是放弃的路;还有一条路不能拒绝,那就是成长的路。

如果好好学习,将来拿到一个好offer,走上人生巅峰。
如果不想学习,将来就会失业,回家卖红薯。
这就是选择!

好好学习
不想学习
上学
好offer
卖红薯

代码实现选择语句:

#include <stdio.h>
int main()
{
	int input = 0;//输入的值
	printf("上学:>\n");
	printf("你要好好学习吗(1/0)?:>");
	scanf("%d", &input);

	if (input == 1)
	{
		printf("好offer\n");
	}	
	else
	{
		printf("卖红薯\n");
	}
		
	return 0;
}

输入1,选择好好学习:
好好学习
结果得到好offer

输入0,选择不想学习:
不想学习
结果回家卖红薯


2. 初识循环语句

如何打破这个循环?
有些事必须一直做,比如日复一日的写博客,比如日复一日的学习,好学不倦,慎思不断,明辨不止,笃行不变。

中了五百万
没有中
成为大佬
菜鸟
上学
买彩票
走上人生巅峰
老实学习

循环语句实现假设可以写到30000行代码,可以得到好offer:

#include <stdio.h>
int main()
{
	int line = 0;
	//循环
	while (line < 30000)
	{
		printf("写代码:%d\n",line);//显示写代码的行数
		line++;//名为line的变量增加1 - line = line + 1;
	}
	if (line == 30000)
	{
		printf("好offer\n");
	}
	return 0;
}

运行结果
循环达到写30000行代码时,结果为得到好offer


3. 初识函数

什么是函数

  • 数学

函数的近代定义是给定一个数集A,假设其中的元素为x,对A中的元素x施加对应法则f,记作f(x),得到另一数集B,假设B中的元素为y,则y与x之间的等量关系可以用y=f(x)表示,函数概念含有三个要素:定义域A、值域B和对应法则f。其中核心是对应法则f,它是函数关系的本质特征。
如f(x) = 2*x+5;

  • C语言
    对于函数f(x,y) = x+y,编写一个对应的Add(x,y) = x+y

如何实现函数功能

C语言对x+y功能的实现:

#include <stdio.h>
int main()
{
	int num1 = 0;
	int num2 = 0;
	scanf("%d %d", &num1, &num2);
	int sum = num1 + num2;
	printf("%d", sum);
	return 0;
}

运行结果
运行结果
但此时还不是函数形式

用函数的形式解决:

#include <stdio.h>
Add(int x, int y)//创建两个整型来接收num1和num2
{
	int z = 0;
	z = x + y;
	return z;//返回整型z
}

int main()
{
	int num1 = 0;
	int num2 = 0;
	scanf("%d %d", &num1, &num2);
	//int sum = num1 + num2;
	//函数的方式解决
	int sum = Add(num1, num2);
	printf("%d", sum);
	return 0;
}

运行结果为:
运行结果
这里调用Add函数帮助计算两个数的和。
给Add函数输入了num1和num2,Add(num1, num2)函数完成求和之后把值返回到sum中去。

函数的重要性

看起来在这一次加法的运用中函数的书写非常冗余,但是:

C语言中的函数的作用是可以将一段经常需要使用的代码封装起来,在需要使用时可以直接调用。

如果一段代码经常需要使用时,函数可以使得程序更加模块化,不需要编写大量重复的代码。


4. 初识数组

想要在存十个数:1-10
使用创建变量的方式:

int main()
{
	int a = 1;
	int b = 2;
	int c = 3;
	int d = 4;
	int e = 5;
	int f = 6;
	int g = 7;
	int h = 8;
	int i = 9;
	int j = 10;

	return 0;
}

如果要存很多数的情况下,用创建变量的方式就非常麻烦。
在此引入数组的概念。

什么是数组

数组

一组相同类型的元素的集合

创建一个10个整型1-10的数组:

int main()
{
	//数组 - 一组相同类型的元素的集合
	//10个整型1-10存起来
	int arr[10] = {1,2,3,4,5,6,7,8,9,10};//集合

	return 0;

创建一个5个字符的数组:

int main()
{
	//int a = 1;
	//int b = 2;
	//int c = 3;
	//int d = 4;
	//int e = 5;
	//int f = 6;
	//int g = 7;
	//int h = 8;
	//int i = 9;
	//int j = 10;

	//数组 - 一组相同类型的元素的集合
	//10个整型1-10存起来
	int arr[10] = {1,2,3,4,5,6,7,8,9,10};//集合
	char ch[5] = { 'a','b','c' };//不完全初始化,剩余的默认初始化为0
	return 0;
}

通过监视窗口可以看到:
监视arr
可见数组arr中十个整型都被指定初始化值。

再通过监视窗口观察数组ch:
监视ch
可见数组ch不完全初始化时,剩余的两个字符默认为0。

访问数组中的元素

数组中每一个元素都有下标,C语言中数组的下标从0开始。数组中的各元素的存储是有先后顺序的,它们在内存中按照这个先后顺序连续存放在一起。
在这里插入图片描述
arr[0]访问的是第一个元素1;
arr[1]访问的是第二个元素2;
……
arr[9]访问的是第十个元素10。

打印数组中所有元素

#include <stdio.h>
int main()
{
	 arr[10] = {1,2,3,4,5,6,7,8,9,10};//集合
	int i = 0;
	while (i < 10)//循环
	{
		printf("%d", arr[i]);
		i++;
	}
	return 0;
}

从下标0开始到下标9循环访问数组中的10个元素并打印出来:
打印元素
成功打印!


5. 初识操作符

算数操作符

+			加法
-			减法
*			乘法
/			除法
%			取模(余)

/号两端都为整数,执行整数除法,无法得到小数;
/号两端有一个为小数,执行小数除法,可得到小数。

移位操作符


>>			左移操作符
<<			右移操作符

int a = 2;
int b = a << 1;
左移操作符——移动的是二进制位
a = 2
int整型为4个字节,共32个比特位,不够32位的在数值前面补0
00000000000000000000000000000010
向左移动一位,补0
00000000000000000000000000000100
b = 4

位操作符

&			按位与
|			按位或
^			按位异或

赋值操作符

= 			等号
+=			加等号
-+			减等号
*=			乘等号
/=			除等号
&=			按位与等号
|=			按位或等号
^=			按位异或等号
>>=			左移等号
<<=			右移等号

int a = 2;
a = a + 5;
等价于a += 5;——复合赋值

单目操作符

!			逻辑反操作
- 			负值
+ 			正值
&			取地址
sizeof		操作数的类型长度(以字节为单位)
~			对一个数的二进制按位取反
-- 			前置、后置--
++			前置、后置++
 3. 		间接访问操作符(解引用操作符)
(类型)		强制类型转换

a+b;
+有2个操作数,双目操作符
单目操作符:只有一个操作数

  • 例1:! - 逻辑反操作:
#include <stdio.h>
int main()
{
	//0表示假,非0表示真
	int a = 0;
	int b = 10;
//!把真变成假、假变成真
	printf("%d\n", !a);//1
	printf("%d\n", !b);//0
	return 0;
}

用法(只对操作符a):

int main()
{
	if(a)
	{
		//如果a为真,则..
	}
	if(!a)
	{
		//如果a为假,则..
	return 0;
}
  • 例2:sizeof - 操作数的类型长度:

计算一个变量的大小:

#include <stdio.h>
int main()
{
	//sizeof是一个操作符
	//不是函数,函数后()不能省略,通常sizeof后()不省略
	//计算类型或者变量的大小的
	int a = 10;
	printf("%d\n", sizeof(int));//sizeof求类型后()不可省略,整型占4个字节
	printf("%d\n", sizeof a);//sizeof求变量后()可省略,整型占4个字节
return 0;
}

计算一个数组的大小和数组元素的个数:

int main()
#include <stdio.h>
{
	//10*4 = 40
	int arr[10] = {0};
	//计算的是数组的总大小,单位是字节
	printf("%d\n", sizeof(arr));//10个元素占40个字节
	printf("%d\n", sizeof(arr[0]));//第1个元素占4个字节
	//计算数组元素的个数
	int sz = sizeof(arr) / sizeof(arr[0]);
	printf("%d\n", sz);//40/10 = 10
	return 0;
}
  • 例3:~ - 对一个数的二进制按位取反:
#include <stdio.h>
int main()
{
	int a = 0;
	//~ 按位取反
	printf("%d\n", ~a);//-1
	
	return 0;
}

~ 把所有二进制位中的数字,1变成0,0变成1
整数a = 0
二进制:00000000000000000000000000000000
按位取反后(所有位取反):11111111111111111111111111111111

整数在内存中存储的是补码
一个整数的二进制表示有3种:原码、反码、补码
负整数-1:
原码(最高位为符号位):10000000000000000000000000000001
反码(原码符号位不变,其他取反):11111111111111111111111111111110
补码(反码+1):11111111111111111111111111111111

正整数
原码、反码、补码相同
内存中存储补码,打印显示原码。

  • 例4:–/++ - 前置、后置–/++:

前置++:

#include <stdio.h>
int main()
{
	int a = 10;
	int b = ++a;//前置++ - 先++,后使用
	printf("%d\n", b);//11
	printf("%d\n", a);//11 - a先加到11再赋给b
	return 0;
}

后置++:

#include <stdio.h>
int main()
{
	int a = 10;
	int b = a++;//后置++ - 先使用,后++
	printf("%d\n", b);//10
	printf("%d\n", a);//11
	return 0;
}

可能出题:

#include <stdio.h>
int main()
{
	int a = 1;
	//不建议深入研究 - 浪费时间研究错误的代码
	//在不同的编译器可能会产生不同的结果
	int b = (++a) + (++a) + (++a);//12
	printf("%d\n", b);
	return 0;
}
  • 例5:(类型) - 强制类型转换:
#include <stdio.h>
int main()
{
	int a = 3.14;
	//警告:从“double”转换到“int”,可能丢失数据
	printf("%d\n", a);
	return 0;
}

通过(类型)强制转换:

#include <stdio.h>
int main()
{
	//强制类型转换
	//不推荐使用
	int a = (int)3.14;//括号中写类型
	printf("%d\n", a);
	return 0;
}

关系操作符

>			用于测试“大于”
>=			用于测试“大于等于”
<			用于测试“小于”
<=			用于测试“小于等于”
!=			用于测试“不相等”
==			用于测试“相等”

逻辑操作符

&&			逻辑与
||			逻辑或
  • && - 并且
int main()
{
	int a = 3;//1
	int b = 5;//1
	int c = a && b;//1 - c为真
	return 0;
}
int main()
{
	int a = 3;//1
	int b = 0;//0
	//需要两者都满足
	int c = a && b;//0 - c为假
	return 0;
}

并集

  • || - 或者

交集

条件操作符

exp1 ? exp2 : exp3

条件操作符(三目操作符)
表达式1 ? 表达式2 : 表达式3
exp1成立,exp2计算,整个表达式的结果是:exp2的结果
exp1不成立,exp3计算,整个表达式的结果是:exp3的结果

  • 例:
#include <stdio.h>
int main()
{
	int a = 0;
	int b = 3;
	int max = 0;

	//if (a > b)
	//	max = a;
	//else
	//	max = b;
	//↓可用条件操作符表示↓
	max = a > b ? a : b;//条件操作符(三目操作符)

	printf("%d\n", max);//3

	return 0;
}

逗号表达式

exp1, exp2, exp3, …expN

逗号表达式:逗号隔开的遗传表达式

#include <stdio.h>
int main()
{
	//(2, 4 + 5, 6);//逗号表达式
	int a = 0;
	int b = 3;
	int c = 5;
			//a = 5		c = 1	   b = 3
	int d = (a = b + 2, c = a - 4, b = c + 2);
	//逗号表达式是从左向右依次计算的
	//整个表达式的结果是最后一个表达式的结果
	//a = 5, c = 1, b = 3, **d = 3**
	printf("%d\n", d);//3
	return 0;
}

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

[]			下标引用
()			函数调用
.			结构体.成员名
->			结构体->成员名
  • []下标引用:
#include <stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	//			 下标0,1,2,3,4,5,6,7,8,9
	printf("%d\n", arr[5]);//6 - []下表引用操作符 - [5]对应第六个元素
	return 0;
}
  • ()函数调用操作符:
#include <stdio.h>
int main()
{
	//调用函数的时候,函数名后的() - 函数调用操作符
	printf("Hello\n");//接受一个操作数
	//	  ↑         ↑
	printf("%d\n",100);//接受两个操作数
	return 0;
}

6. 初识常见关键字

C语言提供的关键字

  1. C语言提供的,不能自己创建关键字
  2. 变量名不能是关键字

不能这么写!

int main()
{
	int char;//err
}

变量名不能是关键字。

常见关键字

auto break case char const continue default do double else enum extern float for goto if int long register return short signed sizeof static struct switch typedef union unsigned void volatile while

介绍常见关键字

define / include并不是关键字,是预处理指令
下列加粗标注的关键字将在本文中具体介绍:

auto - 自动的意思,修饰局部变量,表示自动生命周期
 
break - 停止,中断的意思,用于循环语句,switch-case选择语句
 
case - 用于switch-case选择语句,标记switch选择结构中程序开始执行的位置
 
char - C语言内置数据类型,用于定义字符变量
 
const - 常属性,修饰变量使变量值不能被改变
 
continue - 继续的意思,用于循环语句,不能用于switch语句
 
default - 用于switch-case语句,是switch-case语句里面的默认选项
 
do - 用于do-while循环
 
double - C语言内置数据类型,用于定义双精度浮点型变量
 
else - 用于if-else语句
 
enum - 枚举关键字,创建枚举类型
 
extern - 用来声明外部符号的(其它源文件的变量、函数)
 
float - C语言内置数据类型,用于定义单精度浮点型变量
 
for - 用于for循环语句
 
goto - 用于goto语句
 
if - 用于if-else语句
 
int - C语言内置数据类型,用于定义整型变量
 
long - C语言内置数据类型,一个long用于定义长整型变量,两个long用于定义更长的整形变量(关键字里没有long long,这里介绍的是关键字,long有了,就可以构成long long)
 
register - 寄存器关键字
 
return - 返回,用在函数里
 
short - C语言内置数据类型,用于定义短整型变量
 
signed - 有符号数(有正负之分)
 
sizeof - 计算所占内存空间的大小,单位是字节
 
static - 静态的意思,用于修饰变量,函数
 
struct - 创建结构体类型的关键字
 
switch - 用于switch-case语句
 
typedef - 类型(重)定义
 
union - 联合体(共用体),在某种程度上类似结构体struct的一种数据结构
 
unsigned - 无符号数(没有符号位,没有正负之分)
 
void - 无,空,没有的意思
 
volatile - 易变的意思,如果懂volatile,说明你C语言段位很高,否则C的提升空间还是蛮大的(具体学习Linux操作系统时应用)
 
while - 用于while循环语句,do-while循环语句

auto关键字

auto是自动的,每个局部变量都是auto修饰的。在C语言中,使用auto修饰的变量,是具有自动存储器的局部变量,意味着该局部变量进入作用域自动创建,出了作用域自动销毁,但很少有人去使用它,常省略。

int main()
{
	{
	//进{内创建
	int a = 10;//自动创建,自动销毁 - 自动变量
	//局部变量 - 自动变量 ,本质上应该是auto int a = 10;但是auto一般省略掉
	//auto 新的C语言语法中也有其他用法 - 暂时不学习
	}
	//出}外销毁
	return 0;
}

extern关键字

extern用来声明外部符号的(其它源文件的变量、函数)

如果不用extern声明外部符号(来自其它源文件的),变量会报错,函数不会报错,但最好都用extern声明一下

具体例子可以看static关键字里的修饰全局变量和函数里的例子

register关键字

register是寄存器关键字

  • 什么是寄存器呢?

寄存器是存储空间,在电脑上一般是集成到CPU上的,所以和内存是不同的独立的存储空间。

  • 计算机上的存储空间都有哪些呢?

网盘                       网络上的存储空间
硬盘                       500GB,1TB等
内存                       8GB,16GB等
高速缓存(cache)   几十MB
寄存器                   空间极小
 
造价依次增加,速度依次提高,空间也越小。

  • 为什么出现寄存器和高速缓存呢?

CPU中央处理器,负责运算;
 
早期数据存储在在内存里,当处理数据时交给CPU处理,处理完再将数据交还给内存,因为早期内存的读写速度和CPU的处理速度是相差不大的,所以没有出现寄存器和高速缓存;
 
后来随着技术的发展,内存的读写速度改进不大,但是CPU的处理速度越来越快,可以说CPU的速度甩内存一条街,CPU处理得再快,内存读写速度还是很慢的话也没有什么意义了,因此人们在计算机的设计上,在内存之上放一个高速缓存,高速缓存之上再设一个寄存器,提高读写速度,与CPU处理速度匹配;
 
寄存器和高速缓存之间相互交换数据,高速缓存和内存之间相互交换数据,使得计算机的效率得到了很好地提升;
 
所以当我们写的代码创建的变量放在寄存器里,代码的运行效率就会更高。

int main() 
{
	//大量/频繁被使用的数据,想放在寄存器中,提升效率
	//编译器会自动把有必要的数据放到寄存器中
	register int num = 100;//建议num的值存放在寄存器中
	//是否放在寄存器中由编译器最终决定
	//既然num放在寄存器里,所以num是不能取地址的,取地址会报错
	&num;//取地址是取内存的地址,而寄存器不是内存,这一行是错误的代码,error
	return 0;
}

但是如果程序员都觉得自己的数据重要,都想放在寄存器里面去,但是寄存器的数量就这么小,不够用,会造成灾难性的后果;因此这里的register只是建议把num放在寄存器里面去,是否真的放在寄存器里由编译器最终决定
 
register创建的变量是放在寄存器里的,不能取地址,&取地址取得是在内存中的地址。

static关键字

static关键字是静态的意思,用来修饰局部变量,全局变量和函数。

  1. static修饰局部变量

没有使用static修饰局部变量的代码:

#include <stdio.h>
void test()//空类型,不需要返回值
{
	//每次进入范围创建局部变量a
	int a = 1;//创建a=1
	a++;
	printf("%d ", a);//打印2
}
	//每次走出范围销毁局部变量a
int main()
{
	int i = 0;
	while (i < 10) {
		test();//调用test函数 - 创建局部变量a,销毁局部变量a
		i++;
	}
	return 0;
}

打印结果为2 2 2 2 2 2 2 2 2 2 ,a是局部变量,每次进入函数创建,出函数销毁,因此每次都是打印2。
 
使用static修饰局部变量的代码:

#include <stdio.h>
void test()
{
	static int a = 1;//改变了局部变量a的生命周期,没有改变作用域
	//static代替auto修饰int a ,auto表示自动创建和销毁,static表示只执行一次创建过程
	//静态局部变量在编译时候赋予初值,每次调用函数不再重新赋初值,函数结束不销毁
	a++;
	printf("%d ", a);
}
int main()
{
	int i = 0;
	while (i < 10) {
		test();
		i++;
	}
	return 0;
}

打印结果为2 3 4 5 6 7 8 9 10 11
 
static修饰的局部变量,改变了变量的生命周期,本质上改变了变量的存储类型,让静态局部变量出了作用域依然存在,到程序结束,生命周期才结束。但是作用域没有改变(不影响作用域),出了这个test函数依然不能使用a这个变量,比如在main函数使用a是不可能的。

  1. static修饰全局变量

没有使用static修饰全局变量的代码:

#include <stdio.h>
//test1.c
int g_val = 2021;

//test2.c
extern int g_val;//声明外部符号extern,变量、函数都可以extern声明
int main()
{
	printf("%d", g_val);//如果不用extern声明外部符号(来自其它源文件的),会报错
	return 0;
}

默认全局变量是具有外部链接属性的,其他源文件使用该全局变量需要声明。
 
使用static修饰全局变量的代码:

#include <stdio.h>
//test1.c
static int g_val = 2021;
          //static修饰全局变量,其他源文件即使声明也不能使用
          //改变了链接属性

//test2.c
extern int g_val;//static修饰全局变量,其他源文件即使声明也不能使用
int main()
{
	printf("%d", g_val);
	return 0;
}

如果全局变量被static修饰,使得全局变量的外部链接属性变成了内部链接属性,这个时候这个全局变量只能在本源文件内部使用,其他源文件无法链接到,也无法使用这个静态的全局变量了!

  1. static修饰函数

基本和全局变量类似
没有使用static修饰函数的代码:

#include <stdio.h>
//test1.c
int Add(int x, int y)
{
	return x + y;
}

//test2.c
extern int Add(int x, int y);//不用extern声明也可以运行(不会报错),但是语法规定最好还是写上
//变量要声明,函数也最好声明一下
int main()
{
	int a = 10;
	int b = 20;

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

	return 0;

默认函数是具有外部链接属性的,其他源文件使用需要声明。
 
使用static修饰函数的代码:

#include <stdio.h>
//test1.c
static int Add(int x, int y)
//只能在所在源文件内部使用
{
	return x + y;
}

//test2.c
extern int Add(int, int);
//static修饰函数Add时,其他源文件无法使用

int main()
{
	int a = 10;
	int b = 20;

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

	return 0;
}

和static修饰全局变量相似,如果函数被static修饰,使得函数的外部链接属性变成了内部链接属性,这个时候这个函数只能在本源文件内部使用,其他源文件无法链接到,也无法使用!

typedef关键字

typedef是类型重定义关键字。

typedef可以将一个类型重新定义为一个新的名字:

//将unsigned int 重命名为 u_int, 所以u_int也是一个类型名
typedef unsigned int u_int;
//复杂的类型简单化
int main()
{
	unsigned int num1 = 100;//无符号整型变量
	u_int num2 = 100;//unsigned int被重定义为u_int - 别名
	//num1和num2两个变量的类型是一样的
	return 0;
}

总结

本文初步介绍了选择语句、循环语句、函数、数组、操作符、常见关键字,帮助更好地认识C语言。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

H3T

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值