C语言基础
C语言
前言
C语言背景知识:丹尼斯·里奇,由美国贝尔实验室在1978.1.1提出的
C语言能做什么:
①操作系统
②驱动开发
③引擎开发
④游戏开发
⑤嵌入式开发
软件选择
Visual Studio2022:适合个人以及企业使用。
使用注意:
①安装时选择c++桌面开发即可,并且要带上对应windows系统的SDK。这里我带的是后缀20多的版本
②创建的c文件都要放在源文件当中
③创建c文件时,选择第一个C++文件,但一定要手动把.c后缀带上。、
④一个项目只能有一个main主入口,因此想要执行一个c文件时,把其他的先暂时注释掉。
结构分析
头文件:预处理。即提前要找到需要用的东西。
1 | 如#include<stdio.h> #引入输入输出 |
主入口:固定main()。若为int main(),然后0表示程序正常结束,非0是异常结束。
执行流程
①编写。创建文件,并编写c代码。
②编译。把文件编译为0和1的文件,给操作系统看的,后缀为.obj
③组合。将.obj和头文件组合起来变成可执行的.exe文件
④运行。
注意:c语言程序是从main入口,从上到下执行。
VS2022使用技巧
1 | ①按住ALT进行拉能竖着选择 |
核心语法
注释
单行注释: // 注释内容
多行注释:/* 注释内容 */
注释快捷键:ctrl + K和ctrl + C组合按键
取消注释键:ctrl + K和ctrl + U组合按键
关键字
概述:被c语言赋予了特殊含义的英文单词
特点:
①关键字的字母全部小写
②常用的代码编辑器,针对关键字有特殊的颜色标记,非常直观.
常量
概述:在程序的执行过程中,其值不能发生改变的数据
分类:
①整型常量:正数、负数、0
②实型常量:所有带小数点的数字
③字符常量:单引号引起来的字母、数字、英文符号。注意只能是这3种
④字符串常量:双引号引起来.
注意:
①实型常量小数点前后为0,可以省略
②科学计数法是实型常量,但是要写E
输出常量
printf(参数1,参数2)
参数1:必填。输出内容的最终样式以字符串的形式体现。
参数2,选填。填补的内容
例子:printf(“我的身高:%f米”, 1.73);
格式控制符
即占位符
①整型:%d #decimal
②实型:%f #floating-point
③字符:%c #character
④字符串:%s #string
换行符:
①windows:\r\n #这里\r叫回车符表示回到行首,\n表示换行。这里只写\n也会换行
②mac:\r
③Linux:\n
例子:printf(“我的身高:%f米\n”, 1.73);
制表符:\t。
概述:长度可变的空格。会根据前面字母的个数在后面补空格,让整体的长度达到8或者8的倍数,最少补1个,最多补8个
变量
概述:经常发生改变的变量
定义格式:数据类型 变量名;
注意:
①c语言允许先定义再赋值。
②变量名不允许重复定义
③一条语句可以定义多个变量
④变量在使用之前必须赋值
进制数
二进制:由0和1组成,代码中以0b开头。
十进制:由0~9组成,前面不加任何前缀。
八进制:由0~7组成,代码中以0开头。
十六进制:由09还有af组成,代码中以0x开头。
任意进制转十进制
公式:系数*基数的权次幂相加
系数:就是每一位上的数
基数:当前进制数
权:从右往左, 依次为012345….
十进制转其他进制
除基取余法:不断的除以基数(几进制,基数就是几)得到余数,直到商为0,再将余数倒着拼起来即可。、
数据类型
整数
short:短整数,2个字节
int:整数,4个字节,默认整数类型
long:长整数,赋值要带上L后缀,8个字节
long long(C99才提出的):超长整型,后缀是LL,8个字节
注意:可以用sizeof方法,输出占位符为%zu,用来测试各个类型所占字节大小。
有符号整数(也只能和整数搭配)
signed:默认情况,可省略。有符号整数。正数,负数。
unsigned:无符号整数。打印时用%u占位符。同时取值范围会把负数部分的增加到正数部分。例子unsigned int f = 1;
小数
float:单精度小数,以F位后缀。精确小数点6位。4个字节,
double:双精度小数。精确小数点15位。默认小数类型,8字节
long double:高精度小数,精确小数点18位。window占8字节
注意:
①小数的取值范围都比整型的大,他是以科学计数法存储的
②float保留两位小数的占位符位 %.2f
③double保留两位小数的占位符为 %.2lf
字符
char:占一个字节,取值范围就是ASCII码表中的字母,数字,英文符号
取值范围
double>float>long long>long>int>short>char
标识符
概述:代码中所有我们自己起的名字。比如函数名字
规则:
①由数字、字母、下划线(_ )组成
②不能以数字开头
③不能是关键字
④区分大小写
软性规则:
①用英文单词,见名知意
②变量名要全部小写
③代码文件名:全部小写,单词之间用下划线隔开,开头可以用数字
键盘录入
scanf
概述:是scanner format的缩写,是C语言提供的一一个函数。
作用:获取用户在键盘上输入的数据,并赋值给变量
使用:scanf(“占位符” , &变量名) #&是取地址符,如果不使用引用类型的,根本无法通过一个函数修改变量的值。
例子:scanf(“%d”, &a)
注意:
①直接用可能会被报错scanf是不安全的,可以用scanf_s代替
②占位符和后面的变量要一一对应。具体比如%d %d,那对应键盘录入也必须中间用空格隔开。间隔符往往用空格和逗号。
③第一个参数中不写换行
运算符
1 | 算术运算符:+ - * / % |
注意:
①整数计算,结果一定是个整数
②小数计算,结果一定是小数
③整数和小数计算,结果一定是小数
④小数直接参与计算,结果是有可能不精确的
⑤除法不能除以0
⑥取余的时候,运算的数据必须全部都是整数
⑦获取余数的正负,是跟第一个数字保持一致的
自增运算符
它包括了++和–
注意:
①自增和自减放在单独一行,不管在前还是在后是没有影响的
②但后++,如果参与运算,会先按原值进行计算,后自增或自减。
练习
1 | 数值拆分 |
隐式转换
概述:即把一个取值范围小的,转成取值范围大的。系统会帮我们做
规则:
①取值范围小的,和取值范围大的计算,小的会自动提升为大的,再进行运算
②short char类型的数据在运算的时候,先提升为int, 再进行运算
运算注意事项:
①计算时,数据类型不一样不能直接运算,需要转成一样的,才能运算
②a-z对应ASCII为97-,A-Z对应65-
强式转换
概述:即把一个取值范围大的,转成取值范围小的。需要代码编写
格式:目标数据类型 变量名 = (目标数据类型)被强转的数据;
分支结构
if
switch
1 | 执行流程: |
循环结构
for
1 | 技巧: |
while
do{} while(条件)
练习
1 | 1.给你一个整数n,请你判断该整数是否是2的幕次方 |
跳转控制语句
break
概述:直接结束当前循环。跳出当前控制语句
注意:只能写在switch,循环中
continue
概述:结束本次循环,继续下一次循环
注意:只能写在循环中
goto
概述:可以跳转到程序的任意地方
使用:goto 标号; 标号需要标在要跳转语句的前面,如 a : printf(“我到这里了”)
注意:一般只用于跳出循环嵌套。
函数
概述:就是程序中独立的功能。
定义函数的技巧,三个问题:
1.我定义函数,是为了干什么事情?函数体
2.我干这件事情,需要什么才能完成?形参
3.我干完了,调用处是否需要继续使用? 返回值类型。需要继续使用必须写。不需要返回就用void
注意:
①自定义函数一般写在主函数的下方。除非先定义了函数。
数组
概述:是一种容器,可以用来存储同种(隐式转换也是同种)数据类型的多个值
定义:数组类型 数组名[长度]
特点:定义之后长度不可变,
初始化:
静态初始化:数组类型 数组名[长度] = {数据值……}
注意:
①如果数组的长度没有写, 数据值的个数就是数组的长度
②如果数组的长度已经写上,数据值的个数<=长度
③未赋值的部分有默认值。整数为0;小数:为0.0;字符为’\0’;字符串为NULL (什么都没有)
④数组如果在作为函数的参数时,不能给出大小,因为他是作为一个指针变量传过去了。
⑤作为参数传入函数内部,只是把数组的基地址传过去了,从而通过函数会影响数组内部索引的值。
元素访问:数组名称[索引]
1 | 数组与指针 |
二维数组
初始化:必须得给出列数
1 | // 动态分配二维数组 |
指针
概述:一个指针的变量就是保存地址的变量,也称为指向保存地址的一个变量。
定义:int* p,q = &i,10;(注意q是变量,*只会给p) 或者int *p = &i; #这里叫做 *p是一个int数据类型。
使用:
1 | void f(int *p); //在被调用的时候得到了某个变量的地址: |
练习1
1 | ●交换两个变量的值 |
练习2
1 | ●函数返回多个值,某些值就只能通过指针返回,即通过参数进行返回 |
注意:
①一定不能定义了指针变量,还没有指向任何变量,就开始使用指针。
const
指针与const
格式:int * const p = &a; //代表这是一个一旦赋值了,就不能再次修改地址值的指针变量。
格式2:const int *p = &i; //代表了不能通过指针p来对i赋值。p可以重新指向其他地址,i也可也修改值。
注意:判断哪个被const了的标志是const在*的前面还是后面
&操作符
概述:获得变量的地址,他的操作数必须是变量
指针运算
和运算:对指针变量进行++或者+1等一些和操作,代表的是对地址进行++。其他运算同样是对地址操作。
两个指针运算:他们之间做减法,会给出两个指针中间差了几个量,自动帮你除了对应的字节大小。
注意:
①一定要注意数据类型所占字节数(数组中尤其明显)。
②*p++,其中++的优先级更高,常用于数组类的连续空间操作。在某些cpu他也被认为是汇编语言。
③0地址,他是无意义的,可以理解为就是NULL。也代表指针没有真正初始化。
④不同类型的指针大小都是一样的。但是指向不同类型的指针是不能直接互相赋值的。
⑤void*表示不知道指向什么东西的指针
动态内存分配
背景:如果输入数据时,先告诉你个数,然后再输入,要记录每个数据。C99可以用变量做数组定义的大小,C99之前呢?
1 | #include.<stdlib.h> #导入标准库 |
字符串
概述:他是以字符数组的形态存在的,以’\0’(结束标记)结尾的一段字符
头文件:#include<string.h>
定义格式:char 变量名[大小] = “字符串”; #可以先不写长度
例子:char str[内存占用大小] = “aaa”; #注意这个长度是4
内存占用大小的计算方式:
英文: 1个字母,符号,数字占用一个字节
中文:默认情况下,一个中文占用两个字节
结束标记: 1个字节
字符串常量:char *s = “Hello World!”; #s初始化指向一个字符串常量,并且字符串是不能被修改的。注意他和默认的定义格式不一样,默认的能修改
注意:
①字符串以数组的形式存在,以数组或指针的形式访问。更多的是以指针的形式
②两个相邻字符串,会自动做拼接
③不能用运算符对字符串做运算。通过数组的方式可以遍历字符串
④使用scanf读取字符串是读一个单词,通过回车会空格结束,可以用%7s,表示最大录入7个
内部函数库方法:
①size_t strlen(const char *s):返回s的字符串长度(不包括结尾的0)
②int strcmp(const char *s1, const char *s2):比较两个字符串,返回如下
●0:s1==s2
●1:s1>s2
●-1:s1<s2
③char * strcpy(char *restrict dst, const char *restrict src):把src的字符串拷贝到dst,restrict表明src和dst不重叠(C99),返回dst为了能链起代码来。
④char * strchr(const char *s, int c):返回NULL表示没有找到
⑤char * strrchr(const char *s, int C):从右边开始找,返回NULL表示没有找到
枚举
概述:枚举是一种用户定义的数据类型,它用关键字enum。
定义:enum 枚举类型名字{名字0,….,名字n} ; ‘
结构体
概述:结构体属于用户自定义的数据类型,允许用户存储不同的数据类型
定义:struct 结构体名 {结构体成员列表};
通过结构体创建变量的方式有三种:
①struct 结构体名 变量名
②struct 结构体名 量名 = {成员1值,成员2值..}
③定义结构体时顺便创建变量。即在结构体的}后加入初始化的变量名
示例:
1 | struct Student{ |
结构体数组
作用:将自定义的结构体放入到数组中方便维护
创建:struct 结构体名 数组名[元素个数] = { {},{},…{}}
结构体指针
作用:通过指针访问结构体中的成员
利用操作符 -> 可以通过结构体指针访问结构体属性
示例:
1 | //1、创建学生结构体变量 |
结构体嵌套结构体
作用:结构体中的成员可以是另一个结构体
示例:
1 | 例如:每个老师辅导一个学员, 一个老师的结构体中,记录一个学生的结构体 |
结构体作为参数
作用:将结构体作为参数向函数中传递
传递方式有两种:
①值传递(不会影响原本的值)
②地址传递(会跟着形参的改变而改变) #定义的时候传入struct student *p,使用的时候传入&s1。用->访问内部属性
注意:使用地址传递,可以通过const防止内部属性得到修改。