菜鸟入门C语言

文章目录

1.C语言的概述

1.1什么是C语言

我们都知道人与人之间可以通过汉语、英语等自然语言进行交流沟通。

那么人们用什么方式可以和计算机做最直接的交流?

C语言是一门面向过程的计算机编程语言,与C++、C#、Java等面向对象编程语言有所不同。C语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、仅产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。C语言描述问题比汇编语言迅速、工作量小、可读性好、易于调试、修改和移植,而代码质量与汇编语言相当。C语言一般只比汇编语言代码生成的目标程序效率低10%-20%。因此,C语言可以编写系统软件。

当前阶段,在编程领域中,C语言的运用非常之多,它兼顾了高级语言和汇编语言的优点,相较于其它编程语言具有较大优势。计算机系统设计以及应用程序编写是C语言应用的两大领域。同时,C语言的普适较强,在许多计算机操作系统中都能够得到适用,且效率显著。

1.2C语言的特点

  • 代码量小
  • 执行速度快
  • 功能强大
  • 编程自由
  • 可移植性较差
  • 实现代码周期较长
  • 过于自由
  • 对平台库依赖较多

.dil文件就是封装好的库函数文件

C语言的应用领域

  • 网站后台程序
  • 大型游戏引擎
  • 编写另一种语言(py)
  • 编写操作系统和驱动程序
  • 配置微处理器

C语言仅有32个关键字,9种控制语句,34种运算符,却能完成无数功能。

32个关键字

autobreakcasecharconstcontinuedefaultdo
doubleelseenumexternfloatforgotoif
intlongregisterreturnshortsignedsizeofstatic
structswitchtypedefunionunsignedvoidvolatilewhile

9种控制语句

  • if( )~else 条件语句
  • for( )~ 循环语句
  • while( )~ 循环语句
  • do~while( ) 循环语句
  • continue 结束本次循环语句
  • break 中止执行switch或循环语句
  • switch 多分支选择语句
  • goto 转向语句
  • return 从函数返回语句

C语言中一共有34个运算符,大致的优先级别是:初等运算符、单目运算符、算数运算符、关系运算符、逻辑运算符、条件运算符、赋值运算符、逗号运算符。

第一优先级

运算符名称(含义)使用形式结合方式说明
[]数组下标数组名[常量表达式]从左到右
()圆括号(表达式)/函数名(表达式)从左到右
.结构体运算符结构体.成员名从左到右
->指向结构体运算符(指针)结构体->成员名从左到右

第二优先级

运算符名称(含义)使用形式结合方式说明
-符号运算符-表达式从右到左单目运算符
(类型)强制类型转化(数据类型)表达式从右到左单目运算符
++自增运算符++表达式/表达式++从右到左单目运算符
自减运算符–表达式/表达式++从右到左单目运算符
*取值运算符*指针变量从右到左单目运算符
&取地址运算符&变量名从右到左单目运算符
!逻辑非!表达式从右到左单目运算符
~逻辑取反~表达式从右到左单目运算符
sizeof长度运算符sizeof(表达式)从右到左单目运算符

第三优先级

运算符名称(含义)使用形式结合方式说明
/表达式/表达式从左到右双目运算符
*表达式*表达式从左到右双目运算符
%取余整型表达式%整型表达式从左到右双目运算符

第四优先级

运算符名称(含义)使用形式结合方式说明
+表达式+表达式从左到右双目运算符
-表达式-表达式

第五优先级

运算符名称(含义)使用形式结合方式说明
<<左移变量<<表达式从左到右双目运算符
>>右移变量>>表达式

第六优先级

运算符名称(含义)使用形式结合方式说明
>大于表达式>表达式从左到右双目运算符
>=大于等于表达式>=表达式
<小于表达式<表达式
<=小于等于表达式<=表达式

第七优先级

运算符名称(含义)使用形式结合方式说明
==等于表达式==表达式从左到右双目运算符
!=不等于表达式!=表达式

第八优先级

运算符名称(含义)使用形式结合方式说明
&按位与表达式&表达式从左到右双目运算符

第九优先级

运算符名称(含义)使用形式结合方式说明
^按位异或表达式^表达式从左到右双目运算符

第十优先级

运算符名称(含义)使用形式结合方式说明
|按位或表达式|表达式从左到右双目运算符

第十一优先级

运算符名称(含义)使用形式结合方式说明
&&逻辑与表达式&&表达式从左到右双目运算符

第十二优先级

运算符名称(含义)使用形式结合方式说明
||逻辑或表达式||表达式从左到右双目运算符

第十三优先级

运算符名称(含义)使用形式结合方式说明
?:条件运算符表达式1?表达式2:表达式3从右到左三目运算符

第十四优先级

运算符名称(含义)使用形式结合方式说明
=赋值变量=表达式从右到左双目运算符
/=除后赋值变量/=表达式
*=乘后赋值变量*=表达式
%=取余后赋值变量*=表达式
+=加后赋值变量+=表达式
-=减后赋值变量-=表达式
<<=左移后赋值变量<<=表达式
>>=右移后赋值变量>>=表达式
&=按位与后赋值变量&=表达式
^=按位异或后赋值变量^=表达式
|=按位或否赋值变量|=表达式

第十五优先级

运算符名称(含义)使用形式结合方式说明
,逗号运算符表达式,表达式,表达式,…从左到右

1.3第一个C语言程序

编写helloWorld.c程序

#include<stdio.h>//导入一个文件:stdio是标准输入输出库
int main() {//int 表示函数的返回值为整形
	//main 程序的主函数,
	int a = 123;
	printf("hello world!!\n");
	printf("%d\n", a);// %d是一个占位符,表示输出一个整型数据
	return 0;
}

gcc编译程序

gcc -o hello.exe hello.c
gcc -o hello *.c
arm-linux-gcc -o test.out *.c

1.4system函数

system是一个C/C++的函数。 在windows操作系统下system () 函数主要是在C语言中的应用,system函数需加头文件#include<stdlib.h>后方可调用。 系统命令就是一些基于cmd的命令。

通过system命令打开计算器

#include<stdlib.h>
int main(void) {
	system("calc");
	return 0;//如果命令正确执行了。返回值为0 如果命令执行错误,返回值为其他值。
}

常见cmd命令

命令描述
ipconfig查看ip地址
netstat查看网络连接状态
netstat -ano查看网络连接、状态以及对应的进程id
shutdown关机 -f强制关闭、-p无超时或警告的关机、-s -t 60 定时关机
shutdown -r关机并重启
shutdown -l注销当前用户
shutdown -r -t 秒数一段时间后重启
shutdown -a解除命令
cls清除屏幕
exit退出cmd
notepad打开记事本
dxdiag检查DirectX信息
winver检查Windows版本
wmimgmt.msc打开windows管理体系结构(WMI)
wscriptwindows脚本设置
write写字板
wiaacmgr扫描仪和相机
calc计算器
mspaint画图板
mstsc远程桌面连接
mmc打开控制台
devmgmt.msc设备管理器
taskmgr任务管理器
explorer文件资源管理器
regedit.exe注册表
perfmon.msc计算机性能监测
eventvwr事件查看器
net user查看用户
whoami查看当前用户
net user %username% 123456将电脑用户密码修改为123456,%%中填写用户名称(慎用)
ESC清除当前命令行

电脑快捷键

快捷键描述
win+E打开文件管器
win+D显示桌面
win+L锁计算机
alt+F4关闭当前程序\文件
ctrl+shift+Esc打开任务管理器(或者ctrl+alt+delete)
ctrl+F在一个文本或者网页里面查找,相当实用(退出一般按ESC)
ctrl+A选中所有文本,或所有文件
crtl+alt+tab选中窗口但不打开,使用回车打开。按tab或←→切换
alt+tab选中窗口并打开
win+tab任务视图
ctrl+tab切换窗口(仅同一软件内多个窗口有效,如浏览器开了许多个网页)

1.5C语言程序编译过程

C代码编译成可执行程序经过4步:

  • 预处理:宏定义展开、头文件展示、条件编译等,同时将代码中的注释删除,这里并不检查语法。
  • 编译:检查语法,将预处理后的文件编译生成汇编文件。
  • 汇编:将汇编文件生成目标文件(二进制文件)。
  • 链接:C语言写的程序是需要依赖各种库文件的,所以编译之后还需要把库链接到最终的可执行程序中去。

文件大小单位换算

单位描述
bit比特位,是计算机表示数据最小的单位
byte字节,1byte=8bit
B(字)1byte=1B(Unicode编码中,一个英文为一个子节,一个中文为两个子节)
KB1KB=1024B
MB1MB=1024KB
GB1GB=1024MB
TB1TB=1024GB
PB1PB=1024TB
EB1EB=1024PB

常见编码方式

ASCII 码

美国信息交换标准代码是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言。它是最通用的信息交换标准,并等同于国际标准 ISO/IEC 646。ASCII第一次以规范标准的类型发表是在1967年,最后一次更新则是在1986年,到目前为止共定义了128个字符 。

Bin(二进制)Oct(八进制)Dec(十进制)Hex(十六进制)缩写/字符解释
0000 00000000x00NUL(null)空字符
0000 00010110x01SOH(start of headline)标题开始
0000 00100220x02STX (start of text)正文开始
0000 00110330x03ETX (end of text)正文结束
0000 01000440x04EOT (end of transmission)传输结束
0000 01010550x05ENQ (enquiry)请求
0000 01100660x06ACK (acknowledge)收到通知
0000 01110770x07BEL (bell)响铃
0000 100001080x08BS (backspace)退格
0000 100101190x09HT (horizontal tab)水平制表符
0000 1010012100x0ALF (NL line feed, new line)换行键
0000 1011013110x0BVT (vertical tab)垂直制表符
0000 1100014120x0CFF (NP form feed, new page)换页键
0000 1101015130x0DCR (carriage return)回车键
0100 00010101650x41A大写字母A
0110 00010141970x61a小写字母a

UTF-8编码

字节格式实际编码位码点范围
1字节0xxxxxxx70 ~ 127
2字节110xxxxx 10xxxxxx11128 ~ 2047
3字节1110xxxx 10xxxxxx 10xxxxxx162048 ~ 65535
4字节11110xxx 10xxxxxx 10xxxxxx 10xxxxxx2165536 ~ 2097151

2.数据类型

基本数据类型、构造类型、指针类型

基本类型

类型存储大小值范围
char1 字节-128 到 127 或 0 到 255
unsigned char1 字节0 到 255
signed char1 字节-128 到 127
int2 或 4 字节-32,768 到 32,767 或 -2,147,483,648 到 2,147,483,647
unsigned int2 或 4 字节0 到 65,535 或 0 到 4,294,967,295
short2 字节-32,768 到 32,767
unsigned short2 字节0 到 65,535
long4 字节-2,147,483,648 到 2,147,483,647
unsigned long4 字节0 到 4,294,967,295

浮点类型

类型存储大小值范围精度
float4 字节1.2E-38 到 3.4E+386 位有效位
double8 字节2.3E-308 到 1.7E+30815 位有效位
long double16 字节3.4E-4932 到 1.1E+493219 位有效位

void 类型

在 C 语言中,void 被翻译为**“无类型”,相应的void *** 为**“无类型指针”**。

void 似乎只有"注释"和限制程序的作用,当然,这里的"注释"不是为我们人提供注释,而是为编译器提供一种所谓的注释。

  • 当函数不需要返回值时,必须使用void限定,例如:void func(int a,char *b)。
  • 当函数不允许接受参数时,必须使用void限定,例如:int func(void)。
序号类型与描述
1函数返回为空 C 中有各种函数都不返回值,或者可以说它们返回空。不返回值的函数的返回类型为空。例如 void exit (int status);
2函数参数为空 C 中有各种函数不接受任何参数。不带参数的函数可以接受一个 void。例如 int rand(void);
3指针指向 void 类型为 void * 的指针代表对象的地址,而不是类型。例如,内存分配函数 void *malloc( size_t size ); 返回指向 void 的指针,可以转换为任何数据类型。

控制语句关键字

控制语句描述
if条件控制语句
else条件控制语句
switch条件分支语句
case条件分支语句
default用在switch分支语句中一般与case搭配使用,含义是缺省的其他条件
for循环语句
do循环语句
while循环语句
break循环约束语句;一般在switch语句中使用
continue循环约束语句;结束本次循环,继续下次循环
goto无责任跳转语句
return在函数中:结束函数;在主函数中:结束主函数的执行

存储类型关键字

存储类型描述
auto用于定义局部变量(函数内部变量)一般不用写
extern声明
register建议性指令
static定义静态的数据(局部、全局变量)、定义静态函数
const定义常量

构造类型

构造类型描述
[]数组类型
struct结构类型
union联合类型
enum枚举类型

其他关键字

关键字描述
sizeof是一种单目运算符:获取某个数据类型所占用空间的字节数
typedef用于定义函数指针、用于对一个已存在的数据类型起别名
volatile被设计用来修饰被不同线程访问和修改的变量,可解释为“直接存取原始内存地址”;volatile提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,告诉编译器对该变量不做优化,都会直接从变量内存地址中读取数据,从而可以提供对特殊地址的稳定访问。

常量与变量

定义常量的方式:宏定义、const(不安全的写法)关键字。

#include<stdio.h>
#define PI 3.1415926//这样是宏定义常量,注意没有分号
void main() {
	//黄瓜3元每斤,购买5斤
	//在整个程序运行过程中其值不会改变的量叫常量,会发生改变的是变量
	const int price = 3;//使用const修饰后不能再修改他的值
	int weight = 5;
	int money = price * weight;
	printf("买菜共花了%d元\n", money);
	//求圆的面积 s = Π*r*r
	//园的周长 L = 2Πr

	const float pi = 3.1416;//常量Π
	float r = 3;//正规写法float r = 2.f 2. 2.0都一样
	float S = pi * r * r;
	float L = 2 * PI * r;
	printf("圆的面积为%f\n",S);//%f输出一个十进制的浮点型,默认保留6位小数
	printf("圆的周长为%.2f\n",L );//保留两位小数,会四舍五入
}

标识符:由字母、数字、下划线组成;不能使用关键字,不能使用数字开头。

整形

整形变量的定义和输出

打印格式含义
%d输出一个有符号的10进制int类型
%o(字母o)输出8进制的int类型
%x输出16进制的int类型,字母以小写输出
%X输出16进制的int类型,字母以大写输出
%u输出一个10进制的无符号数

C语言表示相应进制数

进制描述
十进制以正常数字1-9开头;如123
八进制以数字0开头;如0123
十六进制以0x开头;如0x123
二进制C语言不能直接书写二进制数
#include<stdio.h>
int main01(void) 
{
	//无符号 unsigned  有符号signed
	int a = 10;//默认定义的变量都是有符号的(可以区分正负的)
	signed int b = 10;
	//定义无符号时不得出现负数,否则会得到一个奇怪的值
	unsigned int c = -10;
	//%u是一个占位符,表示输出一个无符号十进制整形数据
	printf("%u\n",c);//4294967286
	return 0;
}
int main()
{
	int a = 123;
	int b = 0123;
	int c = 0xABC;
	//如果输出一个十进制数用%d,八进制用%o,十六进制用%x
	printf("十进制:%d\n",a);//十进制:123
	printf("八进制:%o\n", b);//八进制:123
	printf("十六进制:%x\n", c);//十六进制:abc
	return 0;
}
整形的输入
//解决c4996报错;或者将scanf改成scanf_s
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
	int a;
    //使用scanf_s是为了解决c4996报错
	scanf("%d",&a);//&为取地址运算符,输入时以换行为结束符
	printf("你输入的值是:%d\n",a);
	return 0;
}
整形的格式
数据类型占用空间
short(短整型)2子节
int(整型)4子节
long(长整型)Windows为4子节,Linux为4子节(32位),8子节(64位)
long long(长长整型)8子节

需要注意的是,整型数据在内存中占的字节数与所选择的操作系统有关。虽然C语言标准中没有明确规定整形数据地长度,但long类型整数的长度不能短于int类型,short类型整数的长度不能长于int类型。

当一个小的数据类型赋值给大的数据类型时,不会出错,因为编译器会自动转化。但当一个大的数据类型赋值给一个小的数据类型,那么就可能丢失高位。

#include<stdio.h>
int main() 
{
	int a = 10;
	short b = 20;
	long c = 30;
	long long d = 40;

	printf("%d\n",a);//10
	printf("%hd\n", b);//20
	printf("%ld\n", c);//30
	printf("%lld\n", d);//40

	//sizeof 计算数据类型在内存中占的字节(BYTE)大小
	//1BYTE = 1bit 
	printf("整形:%d\n",sizeof(a));//4
	printf("短整型:%d\n", sizeof(b));//2
	printf("长整型:%d\n", sizeof(c));//4
	printf("长长整形:%d\n", sizeof(d));//8
	return 0;
}
sizeof关键字
  • sizeof不是函数,所以不需要包含任何头文件,他的功能是计算一个数据类型的大小,单位为子节。
  • sizeof的返回值为size_t
  • size_t类型在32位操作系统下是unsigned int,是一个无符号整形。

字符型 吧

字符变量的定义和输出

字符变量用于存储一个单一字符,在C语言中用char表示,其中每个字符变量都会占用1个子节。在给字符变量赋值时,需要用一对英文引号(‘’、“”)把字符括起来

字符变量实际上并不是把该字符本身放到变量的内存单元中去,而是该字符对应的ASCII编码放到变量的存储单元中。char本质就是一个字节大小的整形。

#include<stdio.h>
int main()
{
	char ch = 'a';
	printf("%c\n",ch);//a
	printf("%d\n", ch);//97 此时输出的是ASCII码
	printf("字符的大小:%d\n", sizeof(ch));//1子节
	return 0;
}

浮点型

实型变量也称为浮点型变量,浮点型变量是用来存储小数数值的。在C语言中,浮点型变量分为两种:单精度浮点数(float)、双精度浮点数(double),但是double型变量所表示的浮点数比float型变量更精确。

由于浮点型变量是由有限的存储单元组成的,因此只能提供有限的有效数字。在有效位以外的数字将被舍去,这样可能会产生一些误差。

不以f结尾的常量是double类型,以f结尾的常量(3.14f)是float类型

#include<stdio.h>
int main()
{
	float a = 3.14f;
	double b = 3.14;

	printf("%f\n",a);//3.140000
	printf("%lf\n", b);//3.140000
	return 0;
}
#include<stdio.h>
int main()
{
	float a = 3.14f;
	double b = 3.14;
    
	//%p是一个占位符;可输出 (无符号)16进制形式显示数据所对应的内存地址
	printf("%p\n", &a);//006FFC48
	printf("%p\n", &b);//006FFC38
	return 0;
}

进制的转换

十进制与二进制

十进制转二进制

除2取余法
在这里插入图片描述

二进制转十进制

权值法

在这里插入图片描述

十进制与八进制

十进制转八进制

除8取余法

八进制转十进制

同样是权值法

十进制与十六进制

与上述方法相似

进制转换的规律
十进制二进制八进制十六进制
1111
21022
31133
410044
510155
611066
711177
81000108
91001119
10101012A
11101113B
12110014C
13110115D
14111016E
15111117F
16100002010
  • 十进制与二进制转换可通过8421法则快速实现
  • 三位二进制数转为一位八进制数
  • 四位二进制数转为以为十六进制数
小数的进制转换

十进制的小数转成二进制:小数部分和2相乘,取整数,不足1取0,每次相乘都是小数部分,顺序看取整后的数就是转化后的结果。

在这里插入图片描述

存储单位术语

二进制是计算技术中广泛采用的一种数制。二进制数据是用0和1两个数码来表示的数。他的基数为2,进位规则是“逢2进1”,借位规则是“借一当二”。

当前的计算机系统使用的基本上是二进制系统,数据在计算机中主要是以补码的形式存储的。

术语含义
bit(比特位)一个二进制代表一位,一个位只能表示0或1两种状态。数据传输以“位”为单位。
Byte(子节)一个字节为8个二进制,成为8位,计算机中最小的存储单元就是子节。
术语含义
WORD(双字节)两个字节,16位
DWORD两个WORD,四字节,32位
1b1bit,1位
1B1Byte,1子节,8位
1k,1K1024B
1M(1兆)1024K
1G1024M
1T1024G
1Kb1024bit,1024位
1KB1024Byte,1024子节
1Mb1024Kb = 1024*1024bit
1MB1024KB = 1024*1024Byte

C语言如何表示相应进制数

进制表述方式
十进制正常数字0-9
八进制以数字0开头,如0123
十六进制以0x开头,如0x123
二进制C语言不能直接书写二进制
思考题
  • 在C语言里八进制必须以(数字)0开头、十六进制必须以0x开头。
  • 在C语言里标识符只能由数字、字母、下划线组成(不能以数字开头)。
  • C语言里进制的表现形式有三种,分别是八进制、十进制、十六进制。
  • C语言提供了sizeof运算符主要用于计算数据类型在内存中占的大小。

数据的存储方式

原码

一个数的原码(原始的二进制)有如下特点:

  • 最高位做符号位,0表示正,为1表示负
  • 其他数值部分就是数值本身绝对值的二进制数
  • 负数的原码是在其绝对值的基础上,最高位变为1
十进制数原码
+150000 1111
-151000 1111
+00000 0000
-01000 0000

原码表示简单易懂,与带符号数本身转换方便,只要符号还原即可,但当两个正数相减或不同符号数相加时,必须比较两个数哪个绝对值大,才能决定谁减谁,才能确定结果是正还是负,所以原码不便于加减运算。

反码

对于正数,反码与原码相同。

对于负数,符号位不变,其他部分取反。

十进制数反码
+150000 1111
-151111 0000
+00000 0000
-01111 1111

反码运算也不方便,通常用来作为求补码的中间过渡。

补码

在计算机系统中,数值一律用补码来存储。

  • 统一了零的编码
  • 将符号位与其他位统一处理
  • 将减法运算变为加法运算
  • 两个用补码表示的数相加时,如果最高位(符号位)有进位,则进位会被舍弃

补码的特点:

  • 对于正数:原码、反码、补码相同。
  • 对于负数:其补码为它的反码加1。
  • 补码符号位不动,其他位求反,最后整个数加1,得到原码。
十进制数原码反码补码
+150000 11110000 11110000 1111
-151000 11111111 00001111 0001
+00000 00000000 00000000 0000
-01000 00001111 11110000 0000

补码的运算过程

在这里插入图片描述

数值溢出

当超过一个数据类型能够存放的最大范围时,数值会溢出。

有符号位和最高位溢出的区别:符号位溢出会导致数的正负发生变化,但最高位的溢出会导致最高位丢失。

数据类型占用空间取值范围
char1子节-128到127(-2^7 ~ 2^7-1)
unsigned char1子节0到255(0~2^8-1)
类型限定符
限定符含义
extern声明一个变量,extern声明的变量没有建立存储空间。extern int a;//变量在定义的时候创建存储空间
const定义一个常量,常量的值不能修改。const int a =10;
Volatile防止编译器优化代码
register定义寄存器变量,提高效率。register是建议型指令,而不是命令型的指令,如果cpu有空闲寄存器,那么register就生效,如果没有空闲寄存器,那么register无效。

字符串格式化输入输出

字符串常量
  • 字符串是内存中一段连续的char空间,以’\0’(数字0)结尾。
  • 字符串常量是由双引号括起来的字符序列,如“China”、"C"等都是合法的字符串常量。

字符串常量与字符常量不同:

‘a’字符常量"a"字符串常量
‘a’‘a’ ‘\0’

每个字符串的结尾,编译器会自动的添加一个结束标志位’\0’,即"a"包含两个字符’a’和’\0’。

#include<stdio.h>
int main()
{
	char a = 'a';
	const char * b = "hello\0world";
	//%s是一个占位符,表示输出一个字符串,遇到\0停止
	printf("%s\n",b);//hello
	//%s 会根据*b(指针内存地址)在内存中一直找,直到找到\0才会停止
    char c[4] = "123";//4
	//这里数组的大小最小为4,因为默认有一个\0在结尾
	printf("%s\n", c);
	return 0;
}
printf函数

printf是输出一个字符串,

printf格式字符:

打印格式对应数据类型含义
%dint接受整数值并将它表示为有符号的十进制
%hdshort int短整数
%huunsigned short无符号短整数
%ounsigned int无符号8进制整数
%uunsigned int无符号10进制整数
%x,%Xunsigned int无符号16进制整数,x对应小写字母;X对应大写字母
%ffloat单精度浮点数
%lfdouble双精度浮点数
%e,%Edouble科学计数法表示的数,此处“e”的大小写代表在输出时用的“e”的大小写
%cchar字符型。可以把输入的数字按照ASCII码相应转换为对应的字符
%schar *字符串。输出字符串中的字符,直至遇到字符串中的空字符(‘\0’)
%pvoid *以16进制形式输出指针
%%%输出一个百分号

printf附加格式

字符含义
l(字母l)附加在d,u,x,o前面,表示长整数
-左对齐
m(代表一个整数)数据最小宽度
0(数字0)将输出的前面补上0直到占满指定列宽为止,不可以搭配-使用
m.n(代表一个整数)m指域宽,即对应的输出项在输出设备上所占的字符数。n指精度,用于说明输出的实型数的小数位。对数值型的来说,未指定n时,默认精度为n=6位
#include<stdio.h>
int main() 
{
	int a = 10;

	printf("===%-5d===\n", a);//===10   ===  左对齐,整体数据占5位
	printf("===%5d===\n", a);//===   10===   右边对齐,整体数据占5位
	printf("===%05d===\n", a);//===00010===  在左侧用0补全;只能在左侧补全
	int b = 123456;
	printf("===%5d===", b);//===123456===    输出位数大于5,所以正常输出
} 
#include<stdio.h>
int main()
{
	float a = 3.14;
	//7为整体的位数,2为小数点位数
	printf("==%7.2f==",a);//==   3.14== 3.14前有3个空格
    printf("==%-7.2f==",a);//==3.14   == 加上-为左对齐
	return 0;
}
putchar函数

putchar输出一个char

  • putchar输出字符可以是变量、字符、数字(ASCII码内的数据)、转义字符。
scanf函数
  • scanf通过%转义的方式可以得到用户通过标准输入设备输入的数据
#include<stdio.h>
int main()
{
	char ch;
	scanf_s("%c",&ch);
	putchar(ch);
	printf("\n");
	int a, b;
	scanf_s("%d,%d", &a,&b);//%d,%d ,是分隔符
	scanf_s("%3d,%d", &a, &b);//a的长度为3
	printf("%d\t%d\n",a,b);
	return 0;
}
getchar函数
  • getchar是从标准输入设备读取一个char
#include<stdio.h>
int main()
{
	char ch; 
	//接收键盘获取字符
	ch = getchar();
	putchar(ch);//当输入多个字符时只会接受第一个字符
	return 0;
}

3.运算符与表达式

常见运算符分类

运算符类型作用
算数运算符用于四则运算
赋值运算符用于将表达式的值赋值给变量
比较运算符用于表达式的比较
逻辑运算符用于根据表达式的值返回真值或假值
位运算用于处理数据的位运算
sizeof运算符用于字节数长度

算术运算符

运算符术语示例结果
+正号+3+
-负号-3-3
10+515
-10-55
*10*550
/10/52
%取模(取余)10%31
++前自增a=2;b=++a;a=3;b=3;
++后自增a=2;b=a++;a=3;b=2;
前自减a=2;b=–a;a=1;b=1;
后自减a=2;b=a–;a=1;b=2;
#include<stdio.h>
int main072407()
{
	float a = 10.0;
	int b = 7;
	int c = 10;
	printf("%d\n",c/b);//1
	printf("%f\n", a / b);//1.428571
	return 0;

}
int main072408()
{
	int a = 10;
	int b = 5;
	int c = 3;
	int d = 0;
	printf("%d\n",a%b);//0
	printf("%d\n", a % c);//1
	//printf("%d\n",a%d);//报错;取余只能对整形操作
	return 0;
}
#include<stdio.h>
int main()
{
	int a = 10;
	int b = 1 + a++;
	printf("%d\n",b);//11
	//前自增是在表达式之前进行++再进行表达式运算
	//后自增先进行表达式计算再进行++操作
	int c = 5;
	int d = 1 + ++c;
	printf("%d\n",d);//7
	return 0;

}

赋值运算符

运算符术语示例结果
=赋值a=2;b=3;a=2;b=3
+=加等于a=0;a+=2;a=2;
-=减等于a=5;a-=3;a=2;
*=乘等于a=2;a*=2;a=4;
/=除等于a=4;a/=2;a=2;
%=模等于a=3;a%=a;a=1;
#include<stdio.h>
void main()
{
	int a = 5;
	a %= 3;
	printf("%d\n",a);//2
    int b = 10;
    a += b;
    printf("%d\n",a);//12
    
    int c = 6;
    a -= c;
    printf("%d\n",a);//6
    
    int d = 2;
    a /= d;
    printf("%d\n",a);//3
}

比较运算符

C语言的比较运算中用“1”表示真;“0”表示假。

运算符术语示例结果
==相等于4==30
!=不等于4!=31
<小于4<30
>大于4>31
<=小于等于4<=30
>=大于等于4>=31
#include<stdio.h>
void main()
{
	int a = 4;
	printf("%d\n",a == 4);//1
	printf("%d\n", a >= 3);//1
	printf("%d\n", a <= 3);//0
	printf("%d\n", a != 3);//1
}
#include<stdio.h>
void main()
{
	int a = 10;
	int b = 20;
	int c = 10;
	printf("%d\n",c = ++a <= b*2);//1
	printf("a=%d\n", a);//10
	printf("b=%d\n", b);//20
	printf("c=%d\n", c);//1
}

逻辑运算符

运算符术语示例结果
!!a如果a为假,则!a为真;如果a为真,则!a为假。
&&a&&b如果a和b都为真,则结果为真,否则为假。
||a||b如果a和b有一个为真,则结果为真,二者有一个为假时,结果为假。
#include<stdio.h>
void main()
{
	int a = 10;
	printf("%d\n", ! a);//0
	printf("%d\n", !!a);//1
	int b = 20;
	//
	printf("%d\n",!a && b);//0

}

运算符的优先级

优先级1
运算符名称使用形式
[]数组下标数组名[常量表达式]
()圆括号(表达式)/函数名(形参表)
.成员选择(对象)对象.成员名
->成员选择(指针)对象指针 -> 成员名
优先级2
运算符名称使用形式
-负号运算符-表达式
~按位取反运算符~表达式
++自增运算符++变量名/变量名++
自减运算符–变量名/变量名–
*取值运算符*指针变量
&取地址运算符&变量名
!逻辑非运算符!表达式
(类型)强制类型转换(数据类型)表达式
sizeof长度运算符sizeof(表达式)
优先级3
运算符名称使用形式
/表达式/表达式
*表达式*表达式
%余数(取模)整形表达式%整形表达式
优先级4
运算符名称使用形式
+表达式+表达式
-表达式-表达式
优先级5
运算符名称使用形式
<<左移变量<<表达式
>>右移变量>>表达式
优先级6
运算符名称使用形式
>大于表达式>表达式
>=大于等于表达式>=表达式
<小于表达式<表达式
<=小于等于表达式<=表达式
优先级7
运算符名称使用形式
==等于表达式==表达式
!=不等于表达式!=表达式
优先级8
运算符名称使用形式
&按位与表达式&表达式
优先级9
运算符名称使用形式
^按位异或表达式^表达式
优先级10
运算符名称使用形式
|按位或表达式|表达式
优先级11
运算符名称使用形式
&&逻辑与表达式&&表达式
优先级12
运算符名称使用形式
``
优先级13
运算符名称使用形式
?:条件运算符表达式1?表达式2:表达式3
优先级14
运算符名称使用形式
=赋值运算符变量=表达式
/=除后赋值变量/=表达式
*=乘后赋值变量*=表达式
%=取模后赋值变量%=表达式
+=加后赋值变量+=表达式
-=减后赋值变量-=表达式
<<=左移后赋值变量<<=表达式
>>=右移后赋值变量>>=表达式
&=按位与后赋值变量&=表达式
^=按位异或后赋值变量^=表达式
|=按位或后赋值变量|=表达式
优先级15
运算符名称使用形式
,逗号运算符表达式,表达式…
#include<stdio.h>
void main()
{
    int a = 10;
    int b = 20;
    int c = (a,b);
    printf("%d\n",c);//20
}

类型转换

数据有不同的类型,不同的数据类型之间进行混合运算时必然涉及到类型的转换问题。

转换的方法有两种:

  • 自定转换(隐式转换):遵循一定的规则,由编译系统自动完成。
  • 强制类型转换:把表达式的运行结果强制转换成所需要的数据类型

类型转换的原则:占用内存字节数少(值域小)的类型,向占用内存字节数多(值域大)的类型转换,以保证精度不降低。

#include<stdio.h>
void main()
{
	//隐式转换
	int num = 5;
	printf("%d\n",num/2);//2
	printf("%lf\n", num/2.0);//2.500000

	//强制转换;不会四舍五入,而是去尾
	float p = 3.14;
	float m = p * 2;
	int n = (int)p * 2;
	printf("%.2f\n",m);//6.28
	printf("%d\n", n);//6
    
}
#include<stdio.h>
void main()
{
	float p = 3.567;
	int w = 2;
	int sum = (int)(p * w);
	int sum2 = (int)p * w;
	printf("%d\n",sum);//7
	printf("%d\n", sum2);//6

}

4.程序流程结构

C语言支持最基本的三种程序运行结构:顺序结构、选择结构、循环结构。

  • 顺序结构:程序按顺序执行,不发生跳转。
  • 选择结构:依据是否满足条件,有选择的执行相应功能。
  • 循环结构:依据条件是否满足,循环多次执行某段代码。

if语句

#include<stdio.h>
int main()
{
	int score;
	scanf_s("%d",&score);
	if (score > 700) {
		printf("上清华北大了兄弟\n");
		if (score > 730) {
			printf("专业随便选!");
		}
		else if (score >720 ) {
			printf("选个考古学专业没问题");
		}
	}
	else if (score >= 600) {
		printf("上个双一流吧");
	}
	else {
		printf("再接再厉吧");
	}
	return 0;
}

三只小猪?

#include<stdio.h>
int main()
{
	int a, b, c;
	printf("请输入三只小猪的体重,用空格间隔:\n");
	scanf_s("%d%d%d",&a,&b,&c);
	printf("a猪体重为%d\n", a);
	printf("b猪体重为%d\n", b);
	printf("c猪体重为%d\n", c);
	if (a>b) {
		if (a>c) {
			printf("a猪体重最大");
		}
		else {
			printf("c猪体重最大");
		}
	}
	else{
		if (b > c) {
			printf("b猪体重最大");
		}
		else {
			printf("c猪体重最大");
		}
	}
	return 0;
}

三目运算符

a?b:c;

#include<stdio.h>
int main()
{
	int a = 10;
	int b = 20;
	if (a>b) {
		printf("a大\n");
	}
	else if(b>a){
		printf("b大\n");
	}
	else {
		printf("ab一样大\n");

	}

	//三目
	printf("%d大\n", a > b ? a : b);
	
	return 0;
}
#include<stdio.h>
#define MAX(a,b) (a)>(b)?(a):(b)
int main()
{
	int a = 10;
	int b = 20;
	printf("%d\n", MAX(a, b));//20
	printf("%d\n",a>b?a:b);//20
	printf("%d\n", (a) > (b) ? (a) : (b));//20
	return 0;
}

switch语句

#include<stdio.h>
int main()
{
	int score;
	scanf_s("%d",&score);
	switch (score) {
	case 90:
		printf("优秀的小伙子");
		break;
	case 80:
		printf("良好啦");
		break;
	case 70:
		printf("中等哦");
	case 60:
		printf("及格吧");
	}
	return 0;
}

while语句

#include<stdio.h>
int main()
{
    int i = 0;
    while(i<3){
        printf("%d\n",i);
        i++;
    }
    return 0;
}
#include<stdio.h>
int main()
{
	short a = 0;
	do {
		printf("%d\n",a);
		a++;
	} while (a);
	return 0;
}

dowhile语句

#include<stdio.h>
int main()
{
    int i = 0;
    do{
        printf("%d\n",i);
        i++
    }while(i<10)
}

经典水仙花数

#include<stdio.h>
int main() {
	int a = 100;
	while (a < 999) {
		int g = a % 10;
		int s = a / 10 % 10;
		int b = a / 100 % 10;
		if (((g * g * g) + (s * s * s) + (b * b * b)) == a) {
			printf("%d\n",a);
		}
		++a;
	}
	return 0;
}

数学函数

#include<math.h>

库函数功能说明示例
abs(x)求整数 x 的绝对值abs(-5)=5
fabs(x)求实数 x 的绝对值fabs(-3.14)=3.14
floor(x)求不大于 x 的最大整数(下舍入)floor(3.14)=3.000000
ceil(x)求不小于 x 的最小整数(上舍入)ceil(3.14)=4.000000
log(x)求 x 的自然对数log(2)=0.693147
exp(x)求 x 的自然指数(ex)exp(2)=7.389056
pow(x,y)计算 x的y次方 的值pow(2,5)=32.000000
rand( )产生 0~RAND_MAX 的随机整数rand( )%900+100 生成三位随机整数
sqrt(x)求 x 的平方根(根号xsqrt(36)=6.000000

使用数学函数求水仙花数

#include<stdio.h>
#include<math.h>
int main() {
	int a = 100;
	while (a < 999) {
		int g = a % 10;
		int s = a / 10 % 10;
		int b = a / 100 % 10;
		if ((pow(g, 3) + pow(s, 3) + pow(b, 3)) == a) {
			printf("%d\n", a);
		}
		++a;
	}
	return 0;
}

for语句

c89库写法(当前Linux环境)

#include<stdio.h>
int main()
{
    int i;
	for (i = 0; i < 3;i++) {
		printf("%d\n",i);
	}
}

c99库

或者编译时加上…

gcc -o hello.out hello.c -std=c99

#include<stdio.h>
int main()
{
	for (int i = 0; i < 3;i++) {
		printf("%d\n",i);
	}
}

经典猜数字游戏

产生随机数的步骤

  • 导入头文件#include<time.h>、#include<stdlib.h>
  • 添加随机数种子
  • 获取随机数
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
int main()
{
    //time()用于获取当前时间、srand()初始化随机数种子,rand()获取随机数
	srand((unsigned int)time(NULL));//随机数种子,确保每次随机数不一样
	int value = rand() % 100;
	int num;
	int count = 0;
	printf("请输入一个0-100的数字:\n");
	for (;;) {
		scanf_s("%d",&num);
		count++;
		if (num<value) {
			printf("你猜的数字太小了!再猜一次吧:\n");
		}
		else if (num > value) {
			printf("你猜的数字太大了!再猜一次吧:\n");
		}
		else {
			printf("恭喜你仅用了%d次就猜对了!!!",count);
			break;
		}
	}
	return 0;
}

嵌套循环

双层循环时外层循环执行一次,内层循环执行一个“周期”

#include<stdio.h>
int main() {
	//嵌套循环就是
	for (int i = 0; i < 5;i++) {
		for (int j = 0; j < 5;j++) {
			printf("i=%d,j=%d\n",i,j);
		}
	}
	return 0;
}

三层嵌套实现秒表

#include<stdio.h>
#include <windows.h>
#include<stdlib.h>
int main()
{
	for (int i = 0; i < 24;i++) {
		for (int j = 0; j < 60;j++) {
			for (int k = 0; k < 60;k++) {
				system("cls");
				printf("%02d:%02d:%02d",i,j,k);
				Sleep(985);
			}
		}
	}
}

9*9乘法口诀

#include<stdio.h>
int main()
{
	//外层执行一次,内层执行一"周期"
/*  1*1=0
    1*2=4 2*2=4
	1*3=3 2*3=6 3*3=9
*/
	for (int i = 1; i <= 9;i++) {
		for (int j = 1; j <= i;j++) {
			printf("%d*%d=%d \t",j,i,i*j);
		}
		printf("\n");
	}
	return 0;
}

跳转语句

break语句

在switch条件语句和循环语句中都可以使用break语句

  • 当它出现在switch语句中时,作用是终止某个case并跳出switch结构
  • 当他出现在循环语句中,作用是跳出当前内循环语句,执行后面的代码(外层循环)
  • 当他出现在嵌套循环语句中,跳出最近的内循环语句,执行后面的代码

continue语句

在循环语句中,如果希望立即终止本次循环,并执行下一次循环,此时需要使用continue语句

goto语句

无条件跳转语句,可以在各个函数、循环、程序中任意位置进行跳转。

#include<stdio.h>
int main()
{
	printf("hello world01\n");
	printf("hello world02\n");
	goto FLAG;
	printf("hello world03\n");
	printf("hello world04\n");
	printf("hello world05\n");
	FLAG:
	printf("hello world06\n");
	return 0;
}

输出结果

hello world01
hello world02
hello world06
#include<stdio.h>
int main()
{
	FLAG:
	printf("死循环");
	goto FLAG;
	return 0;
}

数组

在程序设计中,为了方便处理数据,把具有相同类型的若干变量按有序形式组织起来——称为数组。

数组就是在内存中连续的相同类型的变量空间。同一个数组的所有成员都是相同的数据类型,同时所有的成员在内存中的地址是连续的。

数组属于构造数据类型

数组的定义

#include<stdio.h>
int main()
{
	//变量的定义
	//数据类型 变量 = 值
	// 
	//数组的定义
	//数据类型 数组[元素个数] = {值1,值2,...}
	int array[6] = { 1,2,3,4,5 ,6};
	printf("%d\n", array[0]);//1
	return 0;

}

数组在内存中的存储方式及大小

#include<stdio.h>
int main()
{
	int arr[5] = { 5,4,3,2,1 };
	//下标为0的元素地址(每次显示的都是首地址)
	printf("%d\n", &arr[0]);//7338948

	//下标为1的元素地址
	printf("%d\n", &arr[1]);//7338952

	//数组名不可以被赋值,他是一个指向数组首地址的常量
	//arr = 100;
	printf("%d\n", arr); //7338948
	printf("%d\n",sizeof(arr));//20字节 =(数据类型*元素个数)

	return 0;
}

遍历数组

#include<stdio.h>
int main() {
	int arr[] = { 5,4,3,2,1,6,9,8,7 };
	for (int i = 0; i < (sizeof(arr) / sizeof(arr[0]));i++) {
		printf("%d\n",arr[i]);
	}
	return 0;
}
//

十只小猪称体重

#include<stdio.h>
int main()
{
	int arr[10];
	printf("请输入十只小猪的体重:\n");
	for (int i = 0; i < 10;i++) {
		scanf_s("%d", &arr[i]);
	}
	int max = arr[0];
	for (int j = 1; j < sizeof(arr) / sizeof(arr[0]);j++) {
		if (arr[j] > max) {
			max = arr[j];
		}
	}
	printf("最重的猪体重是%d\n",max);

}

数组逆置

#include<stdio.h>
int main()
{
	//数组逆置
	int arr[11] = {1,2,3,4,5,6,7,8,9,10,11};

	int i = 0;//数组起始下标
	int j = sizeof(arr) / sizeof(arr[0]) - 1;//数组结尾下标
	while (i < j) {
		int tmp = arr[i];
		arr[i] = arr[j];
		arr[j] = tmp;
		i++;
		j--;

	}
	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]);i++) {
		printf("%d\n",arr[i]);
	}
	return 0;
}

冒泡排序

排序:数据从无序数据到有序数据的过程

#include<stdio.h>
int main()
{
	int arr[] = {5,2,4,3,6,1,0,9,8,7};
	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]) - 1;i++) {
		for (int j = 0; j < sizeof(arr) / sizeof(arr[0]) - 1 - i;j++) {
			if (arr[j] > arr[j+1]) {
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
	}
	for (int i = 0; i < (sizeof(arr) / sizeof(arr[0])); i++) {
		printf("%d\n", arr[i]);
	}
	return 0;
}

二维数组

二维数组的定义形式

//类型说明符 数组名[常量表达式1][常量表达式2]
//其中 常量表达式1 表示第一维下标的长度,常量表达式2表示第二维下标的长度
 int a[3][4];//定义了一个三行四列的数组,数组名为a其元素类型为整形,该数组的元素个数为3*4个
#include<stdio.h>
int main()
{
	int arr[2][3] = 
	{ 
		{1,2,3},
		{4,5,6}
	};
	printf("%d\n",arr[0][2]);//3
	return 0;
}

二维数组的遍历

#include<stdio.h>
int main()
{
	int arr[3][3] =
	{
		{1,2,3},
		{4,5,6},
		{7,8,9}
	};
	int h = sizeof(arr) / sizeof(arr[0]);//得到行
	int l = sizeof(arr[0]) / sizeof(arr[0][0]);//得到列
	for (int i = 0; i < h; i++) {
		for (int j = 0; j < l; j++) {
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
	return 0;

}

二维数组的地址

#include<stdio.h>
int main()
{
	int arr[2][3] =
	{
		{1,2,3},
		{4,5,6}
	};
	//二维数组首地址
	printf("%p\n",arr);//004FFC20

	//二维数组第一行首地址
	printf("%p\n", arr[0]);//004FFC20

	//二维数组第一行的第一个元素的地址
	printf("%p\n", arr[0][0]);//00000001

	//二维数组第二行首地址
	printf("%p\n", arr[1]);//004FFC2C

	/*
	通过观察发现二维数组的首地址与第一行的首地址一样
	第一行首地址与第二行之间间隔了12子节 3*4=12
	由此可知数组存储的元素他们的地址都是连续的
	*/
		
	return 0;

学生成绩的练习

#include<stdio.h>
int main() {
	/*
	定义一个数组,存储5名学生3门成绩
	求出每名学生的总成绩、平均成绩
	求出每门学科的总成绩、平均成绩
	*/
	int arr[5][3];
	//获取学生成绩
	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]);i++) {
		for (int j = 0; j < sizeof(arr[0]) / sizeof(arr[0][0]);j++) {
			scanf_s("%d",&arr[i][j]);
		}
	}
	//打印学生成绩
	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) {
		//每次执行外层循环时会将sum置0
		int sum = 0;
		for (int j = 0; j < sizeof(arr[0]) / sizeof(arr[0][0]); j++) {
			sum += arr[i][j];
		}
		printf("第%d名学生的总成绩为:%d\t平均成绩为:%d\n ",i+1,sum,sum/3);
	}
	
	return 0;
}

多维数组

多维数组的定义与二维数组类似

数组类型修饰符 数组名 [n1][n2][n3]...

  • int a[3][4][5];
    定义了一个三维数组,数组的名字是a,数组的长度是3,每个数组的元素又是一个二维数组,这个二维数组的长度是4,并且这个二维数组中的每个元素又是一个一维数组,这个一维数组的长度是5,元素类型是int
#include<stdio.h>
int main()
{
	int arr[3][4][5] = //3层5行5列
	{
		{
			{1,2,3,4,5},
			{2,3,4,5,6},
			{3,4,5,6,7},
			{4,5,6,7,8},

		},
		{
			{5,6,7,8,9},
			{6,7,8,9,10},
			{7,8,9,10,11},
			{8,9,10,11,12},
		},
		{
			{0,1,2,3,4},
			{1,2,5,8,9},
			{1,4,7,8,5},
			{3,6,9,8,2},
		}
	};
	for (int i = 0; i < 3;i++) {
		for(int j = 0; j < 4;j++) {
			for (int k = 0; k < 5;k++) {
				printf("%d\t",arr[i][j][k]);
			}
			printf("\n");
		}
	}
	printf("三维数组大小:%d\n", sizeof(arr));//240 = 3*4*5*4字节
	printf("三维数组一层大小:%d\n", sizeof(arr[0]));//80 = 4*5*4子节
	printf("三维数组一行大小:%d\n", sizeof(arr[0][0]));//20 = 5*4子节
	printf("三维数组元素大小:%d\n",sizeof(arr[0][0][0]));//4子节

	printf("层小:%d\n", sizeof(arr)/sizeof(arr[0]));//3
	printf("行:%d\n", sizeof(arr[0])/sizeof(arr[0][0]));//4
	printf("列:%d\n", sizeof(arr[0][0])/sizeof(arr[0][0][0]));//5

	return 0;
}

字符串

#include<stdio.h>
int main()
{
	//定义一个字符数组
	char arr[5] = {'h','e','l','l','o'};//一个char类型占1子节
	//定义一个字符
	char c = 'a';

	printf("%d\n",sizeof(arr));//5 = 5*1子节
	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]);i++) {
		printf("%c",arr[i]);//hello
	}
	return 0;
}

字符数组与字符串有什么区别?

#include<stdio.h>
int main()
{
	//定义一个字符数串
	const char* str = "hello";
	//她两是一样的
	char str2[6] = { 'h','e','l','l','o','\0'};
	char str3[6] = { 'h','e','l','l','o',0 };
	printf("%s\n", str2);//hello
	printf("%s\n", str3);//hello
	//定义一个字符数组
	char arr[5] = { 'h','e','l','l','o' };

	//他们有什么区别呢?
	printf("%s\n",str);//hello

	for (int i = 0; i < sizeof(str3) / sizeof(str3[0]); i++) {
		printf("%c", str3[i]);//hello
	}
	//首先他们都是一组字符的集合
	// 字符的打印格式为%c;字符串的打印格式为%s
	//字符串结束标志为\0,也就是说字符串可以写成字符数组的格式,但是一定要有\0作为结束标志
	//也就是说字符串就是字符数组的一个特例(有\0结尾)
	return 0;
}

字符数组与字符串的区别

  • C语言中并没有字符串这种数据类型,可以通过char的数组来替代

  • 字符串一定是一个char的数组,但char的数组未必是字符串

  • 数字0(等价\0)结尾的char数组就是一个字符串,但如果char数组没有以数字0结尾,那么就不是一个字符串,只是普通的字符数组,所以字符串是一种特殊的char数组

字符串的获取

scanf_s()

//#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
	//定义字符数组,获取字符串
	char ch[10];

	scanf_s("%s",ch,sizeof(ch));//char本身就是一个地址,所以不用&取地址符
	printf("%s",ch);
	return 0;
}

gets_s()

#include<stdio.h>
int main()
{
	char ch[100];
	//通过键盘获取一个字符串
	gets_s(ch);//可以带空格,
	printf("%s\n",ch);
	scanf_s("%[^\n]",ch,sizeof(ch));//正则表达式,接受非\n的所有内容
	printf("%s\n", ch);
	return 0;
}

fgets()

fgets()在读取一个用户通过键盘输入的字符串的时候,同时把用户输入的回车也作为字符串的一部分。通过scanfgets输入一个字符串的时候,不包含结尾的“\n”,但通过fgets()结尾多了“\n”。fgets()函数是安全的不存在缓冲区溢出的问题。

#include<stdio.h>
int main()
{
	char ch[10];
	fgets(ch,sizeof(ch),stdin);//可以接受空格
	printf("%s",ch);
	printf("%d",sizeof(ch));//10
	return 0;
}

字符串的打印

puts()

#include<stdio.h>
int main()
{
	const char * s = "hello";
	char ch[] = "66\06";
	puts(s);//在输出完成之后会自动加一个/n
	puts(ch);//66[]
	return 0;
}

fputs()

#include<stdio.h>
int main()
{
	char ch[] = "hello world";
	fputs(ch,stdout);//不会自动加\n
	printf("\n");
	printf("%s\n",ch);
	return 0;
}

字符串长度获取

strlen

  • 计算指定字符串的长度(第一个\0之前的有效字符串),不包括字符结束符\n
  • 需要头文件#include<string>
#include<stdio.h>
#include<string>
int main()
{
	char ch[100] = "hello world";
	//计算字符串有效个数
	printf("%d\n",strlen(ch));//11

	//计算数组大小
	printf("%d\n", sizeof(ch));//100

}

函数

函数的分类

C程序是由函数组成的,我们写的代码都是由主函数main()开始执行的。函数是C语言中的基本模块,是用于完成特定任务的程序代码单元。

从函数定义的角度看,函数可以分为系统函数和用户定义函数两种:

  • 系统函数,即库函数。这是由编译系统提供的,用户不必自己定义这些函数,可以直接使用他们,如printf()函数
  • 用户自定义函数:用以解决用户的各种需求

函数的作用

省去重复代码的编写,降低代码重复率

函数的调用

在调用函数时,需要关心5要素

  • 头文件:包含指定的头文件
  • 函数名字:函数名字必须和头文件声明的名字一样
  • 功能:需要知道此函数能干嘛后才调用
  • 参数:参数类型要匹配
  • 返回值:根据需要接收返回值

例:

#include<stdio.h>
//函数定义
int add(int a, int b) {
	return a + b;
};
int main()
{
	int a = 20;
	int b = 30;
	//函数调用
	int c = add(a,b);
	printf("a+b= %d\n",c);
	return 0;
}

声明和定义的区别

  • 声明不需要建立存储空间,如extern int a;
  • 定义变量需要建立存储空间,如int b;

从广义的角度来讲声明中包含着定义,即定义是声明的一个特例,所以并非所有的声明都是定义

  • int b;它既是声明,同时又是定义
  • 对于extern b 来说他只是声明不是定义

一般情况下,把建立存储空间的声明称之为“定义”,而把不需要建立存储空间的声明称之为“声明”。

多文件编程

function.c

int max(int a, int b) {
	return a > b ? a : b;
}

head.h

#pragma once//防止头文件重复包含
//全局变量的定义
//extern int max(int a,int b);
int max(int a, int b);

main.c

#include<stdio.h>
#include "head.h"
int main()
{
	int a = 90;
	int b = 20;
	printf("%d\n", max(a,b));
	return 0;
}

指针

内存

  • 存储器:计算机的组成部分之一,用来存储程序和数据,辅助cpu进行运算处理。(包括RAM、ROM)
  • 内存:内部存储器,暂存数据/运行起来的程序——断电即失。SRAM、DRAM、DDR(双倍速率同步动态随机存储器)系列
  • 外存:外部存储器,长时间保存程序/数据,断电不丢失。ROM、EROM、FLASH、硬盘、光盘。

内存是cpu与硬盘沟通的桥梁

  • 暂时存放cpu中的运算数据
  • 暂时存放与硬盘等外部存储器交换的数据

物理存储器和存储地址空间

物理存储器:实际存在的具体存储器芯片

  • 主板上插装的内存条
  • 显卡上的显示RAM芯片

存储地址空间:存储器编码的空间范围(软件上说的内存地址空间)。

  • 编码:对每个物理存储单元(一个字节)分配一个号码
  • 寻址:可以根据分配的号码找到相应的存储单元,完成数据的读写

内存地址

  • 将内存抽象成一个很大的一维字符数组
  • 编码就是对内存的每一个子节分配一个32位或64位的编号(与32位或者62位处理器相关)
  • 内存编号就是常说的内存地址

内存中的每一个数据都会分配相应的地址:

  • char :占一个子节分配一个地址
  • int : 占4个子节分配4个地址
  • float、struct、函数、数组等
#include<stdio.h>
int main()
{
	int a = 10;
	//int* 是指针数据类型(在基本数据类型后加上*)

	//定义指针类型的变量存储变量地址
	int* p;
	p = &a;//取a对应的地址赋值给p
	//获取a的内存地址
	printf("%p\n", &a);//00EFFA54
	//windows系统在做数据存储时采用的是小端对齐(低位数据存在低位地址中)
	printf("%p\n",p);//00EFFA54
	
	//在32位平台下,所有指针变量指向存储地址的大小都是32位(4子节)
	//在64位平台下,所有指针变量指向存储地址的大小都是64位(8子节)
	printf("%d\n", sizeof(int*));
	printf("%d\n", sizeof(short*));
	printf("%d\n", sizeof(char*));
	printf("%d\n", sizeof(long*));
	printf("%d\n", sizeof(long long*));
	printf("%d\n",sizeof(float*));
	printf("%d\n", sizeof(double*));
	return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

独立寒秋-

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

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

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

打赏作者

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

抵扣说明:

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

余额充值