C语言基础阶段学习

起因:

在大学的一门叫做《微机原理与单片机接口技术》的课中了解到了嵌入式,现在开始往嵌入式方向学习,目前学了c基础阶段,也遇到了一些问题,在这儿里我记录一下我所学的内容

当然,如有错误,还请各位行业大佬指点一二!

一、计算机的基本结构

输入输出设备(键盘,显示器等等)

CPU处理器(控制器,运算器,寄存器

存储器、程序

计算机由上面这些构成!

存储器分为内存和外存

内存:工作存储器,容量较小,读写速度快,掉电数据会丢失

外存:长期保存数据,容量较大,读写速度较慢,掉电数据不会丢失

寄存器:CPU内部存储器,容量最小,读写速度最快

二、计算机的数据表示(进制转化)

分为:数值数据、非数值数据

2.1非数值数据(不能够直接进行算数运算的数据)

例如:字符,图片,声音

ASCII码表:规定了每一个字符以哪八位二进制数表示(1字节 == 8bir)

其中我了解到小写字符比大写字符大32--------(小写转大写:减32)

2.2数值数据(可以直接进行算数运算的数据)

下面是各个进制的构成:

十进制、二进制、八进制、十六进制

十进制:逢十进1:     0~9构成

二进制:逢二进1:     0~1构成

八进制:逢八进1:     0~7构成  

十六进制:逢十六进1: 0~9,a~f构成

为了区分不同的进制:我们给八进制前加0,十六进制前加0x(0X)

76(十进制)  076(八进制)  0x76(0X76)(十六进制,如果A-F是大写,X就要用写)

2.3进制转化

其他进制转十进制:对应的数乘以对应的指数次幂 之和

二进制转十进制:  1010------- ==  0*2^0+1*2^1+0*2^2+1*2^3= 10

八进制转十进制:  054--------- ==  4*8^0+5*8^1 = 44

十六进制转十进制:0xaf4------- ==  4*16^0+15*16^1+10*16^2 = 2804

十进制转其他进制:除以其他进制倒取余数

十进制转二进制:  除2倒取余   43-----------101011

十进制转八进制:  除8倒取余   43-----------053

十进制转十六进制:除16倒取余  43-----------0x2b

二进制与八进制之间的转换:

可以用3位二进制数表示一位八进制数     0~7-----------000~111

二进制和十六进制之间的转换:

可以用4位二进制数表示一个十六进制数   0~9,a~f(0~15)     0~15-------0000~1111
 

三、C语言中32个关键字

关键字:系统预先定义好的,有特殊含义的,并且都是小写,不能重复定义(32个)

数据类型:char、short、int、long、float、double、struct、enum、union、void

控制语句:if、else、switch、case、default、for 、do、while、break、continue、goto

存储类型:auto、static、externregister

const:只读

return:返回函数

signed:有符号数

unsigned:无符号数

sizeof:计算所占内存空间的大小:单位(字节)  sizeof(数据类型)//sizeof(变量名)

typedef:给已有的数据类型起别名;

volatile:防止编译器优化

标识符:程序员自己定义的,一般用来定义变量名,函数名,类型名

  1. 由数字、字母、下划线构成
  2. 第一个不能为数字
  3. 不能和关键字重名

(建议见名知意!!!)

四、常量

程序运行期间,不能也不会被改变的量

4.1字符常量

‘a’,‘B’,‘s’

4.2 整型常量

二进制:1010

八进制:066

十六进制:0xaf5

十进制:99,-2

注意:默认情况下,整形常量为有符号数;

无符号的int类型:98U

Long类型:76L

无符号的长整型:78UL

4.3浮点型常量

小数:3.14   0.00001   10000(浮点型常量包含整形常量)

指数:1e+5 == 100000  1e-5 == 0.00001

%g: 选择小数或者指数中比较合适(比较短)的一种情况进行输出

4.4 字符串常量

“hello”占几个字节

‘h’‘e’‘l’‘l’‘o’‘\0’

(字符串用双引号括起来,字符用单引号括起来)

注意:字符串由‘\0’结尾

4.5 标识常量(宏)

宏只是一个单纯的替换!

#define  宏名  表达式

注意:1、宏名一般用大写,为了和普通的变量区分开来吗,当然小写也可以

      2、宏后没有分号

五、变量

5.1局部变量

定义在函数(任何)体内的变量

5.2全局变量

定义在函数(任何)体外的变量

5.3存储类型

auto、static、extern、register

Auto:修饰的变量存储在栈区,只能修饰局部变量

Static:修饰的变量存储在静态区,即可以修饰全局变量,也可以修饰局部变量,用static修饰的变量叫做静态变量

extern:修饰的变量存储在静态区,只能修饰全局变量

register:修饰的变量存储在寄存器中,只能修饰局部变量

5.3初始化

初始化:定义变量的时候就给他一个初始值!

int a = 10; //初始化

int a;  a = 10;//赋值

注意:

  1. 全局变量如果没有初始化,他的值为0!
  2. 局部变量如果没有初始化,他的值为随机值!

(为了避免随机值,我们一般给局部变量初始化为0!)

auto:修饰局部变量,存储在栈区

register:修饰局部变量的,修饰的变量存储在寄存器中,但是他的内存空间很小,因此,当寄存器已满时,就算用register修饰了,还是存储在栈区

extern:修饰全局变量,存储在静态区

程序可以由多个.c构成,但是有且只能有一个main函数

作用:告诉编译器,该变量已经在其他文件中定义过了

Static: 即可以修饰局部变量,也可以修饰全局变量,存储在静态区

  1. 如果static修饰局部变量:

作用:延长局部变量的生命周期;如果局部变量没有初始化,那么局部变量的值为0;如果初始化了,只能初始化1次;

如果static修饰全局变量:

作用:限制作用域,只能在本文件内使用

5.4生命周期和作用域

5.4.1 生命周期

从开辟空间到空间释放

5.4.2 作用域

使用的范围

局部变量:

生命周期:从定义开始,到模块(距离他最近的大括号)结束;

作用域:大括号内(距离他最近的大括号)

用static修饰的局部变量:

生命周期:从定义开始,到程序结束

作用域:大括号内(距离他最近的大括号)

全局变量:

生命周期:从定义开始,到程序结束

作用域:整个程序

用static修饰的全局变量:

生命周期:从定义开始,到程序结束

作用域:本文件内(本个.c内)

5.5数据类型转换

5.5.1强制类型转换(我们自己去转的)

5.5.2隐式类型转换(编译器去转的)

注意:char、short使用的时候按照:int去用

        float在使用的时候按照:double去用

横向箭头:不管有没有进行混合运算,都会进行转化!

纵向箭头:只有在进行混合运算的时候,才会进行转换!

六、运算符

单算移关与,异或逻条赋

单目运算符,算术运算符,左移右移,关系运算符、按位与、异或 、按位或、逻辑运算符、条件运算符、赋值

6.1算术运算符

+、-、*、/、++、--、%

注意:%不能用于浮点数

++在前:先自加,在赋值

++在后:先赋值,在自加

注意:如果++a和a++单独成立一条语句,那么都相当于给a+1

6.2关系运算符

>  <   >=  <=  ==   !=

注意: 0 < a < 5  //error

注意:等号的书写! ==(判断是否相等)

6.3 逻辑运算符

&&、 || 、 !

&&:

表达式1  && 表达式2

截断法则:有一个为假,结果就为假,前一个为假,后面就不在进行运算了

||:

表达式1 || 表达式2

截断法则:有一个为真,结果就为真,前一个为真,后面就不在进行运算了

6.4 sizeof运算符

Sizeof(数据类型)  sizeof(变量名)

数据类型如何判断:去掉变量名,剩下的就是数据类型!

6.5 三目运算符

表达式1 ? 表达式2 :表达式3

先去判断表达式1是否成立,如果成立,就将表达式2的值作为整个表达式的值,如果表达式1不成立,则将表达式3的值作为整个表达式的值

8.6 逗号运算符

表达式1,表达式2,表达式3,表达式4,.........,表达式n

从左往右依次去计算每个表达式的值,最后,将表达式n的值作为整个表达式的值

注意:逗号运算符的优先级是最低的,因此在使用的时候加上括号!!

6.7 位运算符

& 、 |  、  ~ 、 ^、 << 、 >>

与运算&:都为1,才为1(有一个0,就为0)

或运算|:都为0,才为0(有一个1,就为1)

取反(~):0变1, 1变0

异或(^):相同为0,不同为1

左移(<<):

无符号数:高位丢弃,低位补0

有符号数:符号位不变,高位丢弃,低位补0

右移(>>):

无符号数:低位丢弃,高位补0

有符号数:符号位不变,低位丢弃,高位补符号位

七、三大结构

顺序结构,选择结构,循环结构

7.1顺序结构

语句按照一定的先后顺序去执行

7.2选择结构

7.2.1 单分支选择结构

if(表达式)
{
    语句1;
}

先判断表达式是否成立,如果成立,执行语句

7.2.2 双分支选择结构

if(表达式)

{
    语句1;
}
else
{
    语句2;
}

先判断表达式是否成立,如果成立,就执行语句1,否则,执行语句2;

案例:输入年份,输出该年是平年还是闰年

7.2.3 多分支if选择结构

if(表达式1)
{
    语句1;
}
else if(表达式2)
{
    语句2;
}
else if(表达式3)
{
    语句3;
}
。。。
else if(表达式n-1)
{
    语句n-1;
}
else
{
    语句n;
}

从上往下,依次去判断每个表达式是否成立,如果成立,就执行对应的语句

案例:输入一个成立,判断成绩的等级

85-100:AAAAAAA

70-85: BBBBBBBB

60-70:  CCCCCCCC

60以下:DDDDDDD

7.2.4 switch语句

Switch(表达式)
{
    Case 标号1:
            语句1;
    Case 标号2:
            语句2;
    Case 标号3:
            语句4;
       。。。。
    Case 标号n-1:
            语句n-1;
    Default:
            语句n;
}

注意:

  1. 表达式不能为float类型;
  2. 标号必须为常量;
  3. 当表达式等于标号的时候:执行冒号后面的语句!(如果都不相等,默认执行default后面的语句!)直到switch,case语句结束,或者遇到break语句结束!

结束条件:(停止输出冒号后面的语句的条件)

  1. 遇到break,跳出switch语句
  2. Switch,case语句结束

7.3循环结构

重复的去做一件事

三要素:循环的起始条件、循环的终止条件、循环变量的变化

7.3.1 for循环

for(表达式1 ;表达式2 ;表达式3)

{
   //循环体;
}

表达式1:循环的起始条件

表达式2:循环的终止条件

表达式3:循环变量的变化

先执行表达式1;然后判断表达式2是否为真,如果为真,则执行循环体,然后执行表达式3,以此反复,直至表达式2为假,跳出循环!

 

案例:用for循环实现1-100之和

思考:表达式1,表达式2,表达式3是否可以省略?

省略表达式1:在for循环之外:要给循环变量一个初始值

省略表达式2:死循环

省略表达式3:循环体内实现循环变量的变化

注意:表达式1,表达式2,表达式3都可以省略,但是分号不能省略

for循环的嵌套:

7.3.2while语句

While(表达式)
{
    循环体;
}

判断表达式是否成立,如果成立,则执行循环体,否则,跳出循环

案例:用while语句实现1-100之和

7.3.3do...while语句

do
{
  //循环体
}while(表达式);

先执行循环体;判断表达式是否成立,如果成立,则执行循环体,否则,跳出循环;

案例:用do...while语句不实现1-100之和

区别

while语句:先判断,在执行,语句至少执行0次;

do...while语句:先执行,在判断,语句至少执行1次;

7.3.4 break和continue的区别

(跳出离他最近的一个循环!)

break:跳出switch、case语句;跳出循环

continue:跳出本次循环,进入下一次循环

7.3.5死循环

While(1)
{
   循环体;
}

for(   ;  1  ;  )
{
   循环体
}

7.3.6goto语句

无条件跳转语句

一般格式为:

goto  标号;

标号:

八、数组

一组数据类型相同的元素组成的集合(一堆数据类型相同的数据组合在一起!)

特点:1、数据类型相同   2、地址连续(打印地址:%p)

存储类型  数据类型  数组名[元素的个数];

           Int       a[5];

//相当于定义了一个数组:数组名为:a:数组中有5个元素,这五个元素都是int类型的

数据类型:数组中元素的数据类型

数组的数据类型:int  [5]

数据类型:去掉变量名,剩下的就是数据类型!

开辟的内存空间的大小= sizeof(数据类型)*元素的个数

8.1数组初始化

int arr[5] = {1,2,3};

//a[0] = 1, a[1] = 2, a[2] = 3;  a[3]和a[4] = ?

在进行部分初始化时,未初始化的部分其值为0;因此,利用部分初始化的特点:给数组进行清零!

数组清零: int  arr[100] = {0};

Int a[5] = {1,2,3,4,5};

Int  a[  ] = {1,2,3};//在进行全部初始化时,数组元素的个数是可以省略的,有后面赋值的具体的元素个数来决定!

8.2数组的访问

数组名[下标]

注意:下标从0开始

8.3字符数组

字符数组的本质就是字符串;

给字符数组进行赋值:

1、Char str[10] = { ‘h’,’e’,’l’,’l’,’o’ };

Str[5]----->str[9] ==’\0’;

“hello”  = ‘h’,’e’,’l’,’l’,’o’,‘\0’

2、Char str[10] = “hello”;

//数组名就是数组首元素的地址

//&str[0] == str

8.4字符的输入输出函数

%s:字符串

Printf(“ %s ”, str);

输出:puts(数组名);

        功能:将数组中的内容打印到终端,并且自动换行

        注意:打印到‘\0结束

        puts后会自动添加换行,而printf不会!

输入:Scanf(“%s”,str);

        gets(数组名);

        功能:将输入的字符串保存在数组中,并且在末尾自动添加‘\0’

        注意:gets不会进行越界检查,如果超出范围,就会操作未申请到的内存空间,段错误

        出现段错误的原因:非法操作你没有申请的空间。

8.5二维数组

二维数组:元素为一维数组的一维数组

一组数组类型的元素组成的集合(一堆一维数组组成的数组)

元素:一维数组(元素:一维数组的里面存放的元素的个数以及数据类型必须相同)

数据类型相同   地址连续

存储类型  数据类型  数组名[行数][列数];

九、函数

具有独立功能的模块

为什么要使用函数???

使代码模块化,提高代码的复用率

9.1函数的分类

9.1.1 库函数

printf 、scanf 、strlen 、strcat......

9.1.2引入头文件

#include <stdio.h>、 #include<string.h>

9.1.3 调用函数

Strlen(数组名);

函数名(实际参数);

返回值:字符串的实际长度;考虑:返回值的数据类型,以及返回值是否需要

(如果需要使用函数的返回值:定义一个与其返回值相同的数据类型去接收!)

9.2自定义函数

9.2.1函数定义

存储类型  数据类型  函数名(形式参数列表)

{

函数体;//具体功能的实现

返回值;

}

存储类型:static、extern

数据类型:函数返回值的数据类型(函数返回值:不写默认为:int)

函数名:见名知意(满足标识符的命名规则)

形式参数列表:实现功能所需要的参数,需要调用者传入

函数体:具体功能的实现

返回值:若没有返回值,返回值可以省略(类型:void),如果有返回值:有且只能有一个!

9.2.2调用函数

函数名(实参列表);

注意:

  1. 需要将实参的值传递给形参,实参的个数和数据类型必须和形参一致
  2. 实参,可以是常量、变量、表达式,但必须是一个确定的值;
  3. 实参和形参是两块独立的空间(因此可以重名)
  4. 传参实际上是将实参的值拷贝给形参
  5. 形参是局部变量,在函数调用时开辟空间,调用结束立即释放

 

调用时

调用结束

十、指针

10.1什么是指针?

Char是一种数据类型,它是一种保存字符的数据类型(‘a’,‘b’)

Int 是一种数据类型,它是一种保存整形数的数据类型(10,20)

float是一种数据类型,他是一种保存浮点数的数据类型(3.14  2.37)

指针是一种数据类型,它是一种保存地址的数据类型(%p打印出来的地址编号)

10.2什么是地址?

内存分配的最小单元是字节,每一个字节都有一个编号,这个编号就叫做地址!

地址的本质:内存单元的编号!

指针:

指针:指针就是地址

指针的本质:内存单元的编号

10.3 指针常量

Char定义的变量-----------保存字符常量

Int定义的变量----------保存整形常量

float定义的变量-------保存浮点型常量

指针定义的变量-------保存指针常量(地址:专门用来保存内存单元的编号)

10.4 指针变量

如何定义一个指针变量?

存储类型  数据类型*  变量名;

           Int *     p;

//*用来表示p是一个指针变量

//定义了一个指针变量p,这个p用来保存类型变量的地址

//指针保存谁的地址========等价于===========指针指向谁

数据类型:指针指向的数据类型

指针p的数据类型:int *

指针指向的数据类型:去掉一个*,在去掉变量名,剩下的就是指针指向的数据类型!

注意:*和&互为逆运算;

p保存了a的地址,作用是什么?

  1. 间接访问a的值
  2. 间接改变a的值

 

10.5 指针的赋值

指针的赋值:相当于改变指针的指向;

注意:对指针变量进行赋值时,要注意类型匹配!

10.6空指针

没有指向的指针:NULL(值为0的指针,就认为该指针没有指向)

注意:0号地址禁止操作

要操作就改变指针的指向:

10.7、野指针

不知道指向哪里的指针

局部变量:没有初始化:随机值

局部指针:没有初始化:野指针

如何避免野指针?

在定义指针时:初始化为NULL;

10.8值传递

案例:封装函数实现两个数的交换

10.9地址传递

总结

在近十天内学习了c语言的基础阶段,

哈哈哈,学习C语言就像是和一只顽皮的猴子搏斗!有时候你觉得自己已经掌握了它,结果它又给你来个“语法错误”!但是不管怎样,C语言学习总结就是:坚持不懈,笑到最后!😄🐵

继续加油,继续努力,更上一层楼!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值