C语言基础(超基础篇)

前言:

        本人于大学接触的第一门语言为C++,对C的一些语法有些不了解,为便于嵌入式学习,特开此篇。


第一章、数据类型:

基本数据类型:

        int——整型,4字节;

       char——字符型,1字节;

        float——单精度浮点数,4字节;

        double——双精度浮点数,8字节。

        long (int)——长整型,4或8自己取决于几位机。

在使用一个变脸时,需要先定义类型,来为该变量分配一个内存空间来存储信息。

数组:

        为了方便地定义多个相同类型地变量,引入数组的概念。

        数组是顺序存储的。格式如下:

        数据类型     数组名称[个数];

        如此,便创建了三个数组,a为整型数组含10个元素,b为字符型数组含20个元素,c为双精度浮点数型数组含20个元素。

        以上为一维数组,下面介绍二维数组:

        数据类型   二维数组名[n][m];

        二维数组可以当作是一个矩阵,第一个[]内的为行参,第二个[]为列参;可以看作是一维数组的一维数组。

        下面介绍数组的初始化:

若您想深入了解,可看我往期书写的博客。

数组浅学笔记-CSDN博客

指针:

指针定义、赋值、通过地址取值的方式:

        为什么要使用指针呢?

        除了上述存放的基本数据外,还可以存放地址(相当于你寝室(空间)的门牌号(地址),通过门牌号能找到你的寝室(空间或数据))。如下图所示,通过地址能够访问到a变量的值:

        那么左边那块0x0523的地址变量应该要怎么定义呢?语法如下:

        数据类型*      指针名(ptr);

        数据类型与要执行的地址所属于的变量类型相同。

        知道了指针如何定义后,下面介绍如何初始化指针的值:

        数据类型*    ptr = &变量;

        &为取地址符号,不为右值(简单理解可以记为不在赋值符号右侧)时表示引用(下面介绍)。

        知道了如何初始化后,下面介绍如何取出指针变量里面的值:

        *ptr;

        简单理解,ptr中存放的是地址,而*号代表钥匙,使用*ptr才能去访问该地址中存放的数据。

        

       

指针与一维数组:

        首先我们要知道,数组名代表着什么,数组名实际存放的是数组的首元素的地址。那么我们可以定义指针如下:

        这样有什么好处呢?如此定义指针之后,访问数组的元素就可以分为以下两种方式了:

        1、数组名(地址)[下标(index)或者你可以理解为偏移量];

        2、*(ptr + 下标(index))

        下面的表格第一行为建立的数组a[5],内部元素的值同上的代码图,表格中每列代表的含义相同。

12340
a[0]a[1]a[2]a[3]a[4]
*(a+0)*(a+1)*(a+2)*(a+3)*(a+4)
ptr[0]ptr[1]ptr[2]ptr[3]ptr[4]
*(ptr+0)*(ptr+1)*(ptr+2)*(ptr+3)*(ptr+4)

当然,除了以首地址(数组名)开头,如下的访问也是可以的,只要保证[]前的是地址,内部参数为偏移量即可:

        如要访问a[4]的内容,我们也可以写成(a+4)[0],其本质是无区别的。

指针进阶(有空更新暂不写):

结构体:

结构体类型的定义:

        为什么需要结构体?如果你学过C++,你可以简单地将其看做是只有public的Class。下面给出为什么需要结构体的解释:

        假如现在程序编写中有n个学生,他们都有姓名,学号,性别等,如果按照我们之前提到的数据类型去存储这些信息会十分繁琐,且信息之间是孤立的。但是使用结构体就能够比较好地来存储这类信息。(struct的定义放在main函数外一般习惯)。

        如上定义我们便可以使用结构体student来处理学生的信息啦。

        下面介绍结构体变量的创建:

        上文中我们创建了一个抽象的学生struct student类型,我们可以用该类型去定义变量,从而实现对学生的信息的管理:

        

        但是如上定义结构体,每次定义变量时都要使用struct student,实在太过于繁琐,所以我们通常这样定义:typedef——给一个类型取一个别名,下文就是将struct student取别名为stu。

结构体变量中属性的获取:

        首先我会给出一个单链表的数据结构的struct如下:

        对上述别名的解释,其分为两部分:

        typedef struct LNode LNode;

        typedef struct LNode* Linklist;(即Linklist为结构体指针类型)

        下面介绍结构体与结构体指针的成员如何调用:

        1、结构体:结构体变量名.结构体成员;

        2、结构体指针:结构体指针变量名->结构体成员


第二章、输入与输出:

基本输出printf:

        上文中多次使用了printf()将内容输出到屏幕上,下面简单介绍printf的使用方法:

        1、d格式字符:

                用于整型数据的输出。

                

                当然也可以在%和格式字符间插入格式修饰符,如%5d表示指定输出的数据占5列且自动向右靠齐(空白(若有)在左,数据靠右),左对齐就加个-号。

        2、f格式字符;

                用于实数类型的输出,默认实数部分全部输出,小数部分保留6位;

                

                控制小数部分的方法为在%和f间加入.n(n为要保留的位数):

        3、c格式字符:

                用于输出一个字符;

        

        4、s格式字符:

                用于输出一个字符串;

        当有多个占位符时,从左往右依次匹配对应的。

                

基本输入scanf:

        当我们想要将一个数据写入到变量中时,我们需要找到他的地址,因此需要&符号来取地址(本身为指针就不用取地址啦);

        其格式字符同上,不再赘述;

        这里面的19为限制长度最大为19。(与上文结构体中的定义有关)。


第三章、运算符与表达式:

算数运算符:

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

        +、-、*的运算没有什么好解释的,就略过不谈;

        /当类型均为整型时,为整除,即没有小数点(直接去尾);

        %为去余运算,只能对整形数据;

        ++:分为前置与后置,当前置时,先自增再返回;否则先返回再自增。

        --:同上。

关系运算符:

        >(判断是否大于)、<(判断是否小于)、==(判断是否等于)、>=(判断是否大于等于)、<=(判断是否小于等于)、!=(判断是否不等于);

        需要注意的是关系运算返回的结果为bool值(True or False,非0看为真)。

        

逻辑运算符:

        !(非运算,将bool值取反)、&&(与运算,同真为真,否则为假)、||(或运算,有真为真)。

        &&和||具有短路效应,当表达式1&&表达式2时,若表达式1已经为false,表达式2是不进行任何操作的;对||而言,若表达式1为true则表达式2是没有任何操作的。

条件运算符:

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

        解释,当表达式1的结果为真时,取表达式2的值,否则取表达式3的值。

位运算符:

运算符含义运算符含义
&按位与~取反
|按位或<<左移
^按位异或(不进位的二进制加法)>>右移

为什么要位运算符,实际是为了遍历stm32的地址操作更加便利~。


第四章、程序设计结构:

循环结构:

        while循环:

                语法如下:

        

                其中condition为你要输入的条件变量,code部分为循环体代码;

                什么意思呢,就是当condition的值为true(非0)时,循环体会一直执行,直到condition的值为false(0)时终止循环,由此可见如果想要终止循环,condition的值应该在code部分中会发生改变,不然会死循环(当然在stm32中往往是需要写成死循环的,但一般的程序设计是不允许的。)

                下面来看while循环的特点,可以发现其是先判断循环条件是否成立再进入循环的,也就是说最小的循环次数可以为0。

        for循环:

                语法格式如下:

                参数解释:size_t可以简单地理解为数据类型,i为循环控制的标记,count为你要循环的次数,i++是为了你能够退出循环。

        综上可以看出,while适合于循环次数未知的循环,而for循环则适用于循环次数已知的循环(例如数据的输入之类的)。循环的嵌套我就不展开说了,了解了while和for能看懂的。

选择结构:

        if...else:

                语法如下:

                

                当condition为true时,执行if下的code片段,否则执行else下的code片段。

                其也是可以嵌套的,else自动与最近的if语句组合。

        switch...case:

                语法如下:

                

                这个是什么含义呢,首先通过expression从外界获取一个值,将该值与各个case的值进行匹配,从最上方依次往下匹配,当遇到相等的case时,执行其下方的code,然后通过break跳出循环,否则继续往下遍历,直到default(该处也可以有code)。


第五章、函数:

函数的作用:

        当一个功能在程序中要多次调用时,引入函数的概念可以避免我们进行多次重复的操作啦~比如说我们需要多次交换两个数的值,我们就可以写一个swap()函数来便于我们的调用。

参数传递、返回值:

        函数的返回值:

                首先我们要知道一个函数只能返回一个值,其值通过return函数返回;

                函数的类型决定了函数的返回值类型;

                不需要返回值的函数可以定义为void。

        

        参数的传递:

                在我们定义函数的时候,我们定义的实际上是一个形式参数(重要的是类型),我们在调用函数的时候使用的是实际参数,在编译的过程中实参与形参相融合。

                那么我们来思考一个问题,为什么我上文中交换两个数的值的形参用的是指针(地址)而不是直接将两个数传入进去呢,这就得要返回我们的函数返回值讲起了。因为只能够返回一个值,显然不可能将转换后的两个值都返回回去,所以不能return回值,可能又有人要问,我以及在函数中将两个值进行了交换,为什么输出的时候发现两个值还是和未交换前一样呢?这是因为在C语言中,参数的传递默认是值传递,其会建立一个副本,在函数调用时是对这个副本进行操作而不是对原来的值进行操作,在函数调用结束后这个副本就消失了,所以输出的结果也就变啦。

                因此当函数中有对参数进行改变且想要主函数中同步改变的时候,应该传入指针,在调用时的实参为&参数名。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

江弦凤歌

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

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

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

打赏作者

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

抵扣说明:

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

余额充值