嵌入式学习记录——C语言相关

目录

一、C语言关键字

(一)数据类型

(二)类型修饰符

(三)控制语句

(四)存储类型

(五)其他

二、linux下C开发环境

(一)分析建模

(二)画流程图

(三)将流程图翻译成C语言代码

(四)将C源代码编译成可执行程序(gcc编译器)

(五)执行可执行程序

案例:

定义变量 (在内存中分配空间)

三、C语言库函数

(一)输入:scanf()

(二)输出:printf()

(三)运算符:

四、数据类型的转换

(一)隐式转换(自动转换 范围小---范围大)

(二)强制转换 (范围大--->范围小)

(三)进制转换

五、字符

(一)什么是字符

(二)如何定义字符变量

(三)字符相关操作及运算

六、结构

(一)选择结构

(二)循环结构

七、定义常量

(一)宏定义

(二)const修饰

八、数组

(一)一维数组

(二)二维数组

九、指针

(一)指针的定义

(二)指针的定义方式

(三)指针的指向类型和数据类型

(四)指针的数据类型大小

(五)*p和p

(六)Const修饰指针

(七)空指针和野指针

(八)二级指针

(九)指针数组与数组指针

十、函数

(一)自定义函数

(二)形参和实参

(三)函数的返回值

(四)函数的声明

十一、结构体

一级指针和一维整型数组

一级指针和字符串数组

数组指针和二维数组

指针数组

指针函数

函数指针

Malloc 和free


一、C语言关键字

(一)数据类型

int   float   double   char   long   short   union   struct   enum   void

(二)类型修饰符

const   volatile

(三)控制语句

If   else   for   while   switch   do   case   continue   break    goto   defult

(四)存储类型

auto   static   extern   register

(五)其他

Return   typedef   sizeof   signed   unsigned

32个关键字

标识符的定义规则:1.字母,数字,下划线

2.不能以数字开头,不能和关键字相同

、linux下C开发环境

例如:输入一个数num,判断该数是奇数还是偶数

(一)分析建模

偶数:——>能被2整除的数

奇数:——>不能被2整除的数

(二)画流程图

(三)将流程图翻译成C语言代码

注释:

     单行注释     //

     多行注释     /*      */

入口函数:main

(四)将C源代码编译成可执行程序(gcc编译器)

gcc  1.c  -o   1

(五)执行可执行程序

./ 可执行程序 ——>执行程序

案例:

案例1:输入一个正方形的边长,计算其周长和面积

  1. 分析建模

length=len*4

area=len*len

  1. 画流程图

  1. 将流程图编译C语言代码

定义变量 (在内存中分配空间)

类型名   变量名;

类型名   ----->基本数据类型

               整数    int

               小数    float

                    字符    char

变量名  ------>命名规范

               (1).由数字,字母,下划线组成,首字母不能为数字

               (2).不能为关键字或保留字

               (3).尽量见名知意

三、C语言库函数

#include <stdio.h>

(一)输入:scanf()

scanf(“格式化符号”,地址列表) 有个几个格式化符号,地址就多个

scanf("%md%mf",&r,&f); scanf可以控制宽度,但不能控制精度

(二)输出:printf()

printf(字符串)    printf(“helloworld\n”)  字符串会原样输出

printf(字符串+格式化符号(占位符),变量名列表) 前面有几个格式化符号,后边会多个变量名

%d ---->有符号整数

%f ----->浮点数

%c ----->字符

printf("半径为%md的周长为%-m.nf,面积为%f\n",r,len,area);   

m:数据所占的宽度

n:数据所保留的精度

默认是右对齐,-表示左对齐

 

(三)运算符:

(1)算术运算符

+,-,*,/(整数/整数=整数),%(取模/求余)

7/3=2     11/3=3   11%3=2  %(求余/取模)

+=,-=,*=,/=,%=

a+=1   < == > a=a+1

7/3=2     11/3=3   3.0/2=1.5      11%3=2  %(求余/取模)

a++               ++a

int x=5.5*3+5%4

8. 有整型变量x,单精度变量y=5.5,表达式x=(float)(y*3+((int)y)%4)执行后,x的值为(A)。 

(A)17(B)17.500000(C)17.5(D)16

(2)关系运算符

<,>,<=,>=,=!,==

(3)逻辑运算符

&&(与)有一为假,结果就为假

||(或)有一为真,结果就为真

!(非)

(4)条件运算符(三目运算符)

a>b?a:b     若为真,结果为a,否则b

四、数据类型的转换

(一)隐式转换(自动转换 范围小---范围大)

范围小----->范围大的转换   int  +  float   ---->float

(1)int家族

short    ---->2个字节的整数

int       ----->4个字节的整数

long  ------>4个字节的整数

short                 ----->signed short 有符号的整数

unsigned short  ----->无符号整数

int+float----->float

short +int ---->int

signed+unsigned--->unsigned

(2)float家族

float       ---->4字节

double   ---->8字节

long double

(二)强制转换 (范围大--->范围小)

float  f=13.5

(int)f

(三)进制转换

五、字符

(一)什么是字符

 带单引号称为叫字符

 字符:

转义字符     ‘\n’

‘\012’ ---->1个八进制

          ‘\x12’  ---- >1个十六进制

         非转义字符   ‘a’,’0’,’A’,等

(二)如何定义字符变量

类型名   变量名;

char       ch;

(三)字符相关操作及运算

六、结构

(一)选择结构

(1)单分支选择结构

If(条件为真)

{

     语句

}

(2)双分支选择结构

 if(条件为真)

{

     语句1;

}

else

{

     语句2;

}

(3)多分支选择结构

If(条件1为真)

{

     语句1;

}

elseif(条件2为真)

{

     语句2;

}

elseif(条件3为真)

{

     语句3;

}

·······

elseif(条件n为真)

{

     语句n;

}

else

{

     语句;

}

1.switchcase语句

(1)当条件在某一个点上时,switch,case

(2)表达式的结果类型不能为浮点型

(3)标号必须为常量

(4)当表达式 == 标号时,执行标号后的语句,直到switch,case语句结束为止,或者碰到break语句提前结束。

(5)case和case之间,以及case和defalut之间没有顺序可言

Switch(表达式)

{

     case 标号1:(case和标号1中有空格)

                       语句1

     case 标号2:

                       语句2

     case 标号3:

                       语句3

·····

case标号n:

                  语句n

default:

                  语句n+1

}

(二)循环结构

(1)什么是循环

(2)while语句

1.循环的初始条件

While(2.条件判断)               条件判断,满足什么样的条件循环继续执行

{

           3.循环体

           4.条件更新

}

(3)for语句

循环的初始条件若有多句话的逗号隔开

for(;;)()中有且仅有两个分号

for((1)循环的初始条件;(2)条件判断;(4)条件更新))

{

     (3)循环体

}

(4)break跳出循环

(5)continue

(6)死循环

while(1)

{

}

for(;1;)

{

}

停止是ctrl+c

七、定义常量

(一)宏定义

底行模式输入:%s/关键词1/关键词2/g

(二)const修饰

八、数组

(一)一维数组

(1)如何定义数组

元素的数据类型      数组名[元素的个数]              元素的个数必须为常量

定义一个长度为5的float数组

float     arr[5];

定义一个长度为10的int数组

int         brr[10];

定义一个长度为20的char数组

char      str[20];

(2)数组初始化

1.部分初始化

部分初始化,未初始化的部分,如果是float,int类型会自动默认为0,char会默认为’\0’

Float arr[5]={12,13,45}

(二)二维数组

一维数组的定义:int arr[5];  这是一个有5个int类型元素的一维数组

1 2 3 4 5

 

二维数组的定义:int arr[2][5];  这是一个有2个int arr[5]类型元素的一维数组

1 2 3 4 5  一维数组

1 2 3 4 5  一维数组

二维数组的定义:数据类型  数组名[行数][列数];

行数:有几个一维数组

列数:一维数组的元素个数

所以:二维数组的本质就是数组元素类型为一维数组的数组

初始化:

Int arr[2][5] = {{1,2,3}, {4,5,6,7,8}};

Int arr[2][5] = {1,2,3,4,5,6];

字符二维数组:

Char str[3][10];  这个数组可以存三个字符串,每个字符串长度最大为9

Char str[3][10] = {“abc”, “cdsdf”, “swfeqw”};

Str[0]就是”abc”的首地址(数组名)

Str[1]就是“cdsdf”的首地址

Char str[3][10] = {{‘a’,’b’,’c’,’v’,’h’,’h’,’\0’},{’t’,’y’,’o’,’\0’},{’r’,’t’,’\0’}};

九、指针

指针:本质就是地址

地址是什么?

数据和指令最终都要存放在内存,cpu按照我们写的程序去访问内存,内存本质就是一个一个字节组成的,也就是说我们写的程序要去访问内存的一个个字节进而访问指令或者数据,那要实现这个目的,每个字节都长的一样,如何区分?

给每个字节编号来区分

 

地址:内存的基本单元是字节,每一个字节都有自己的唯一的编号,通过这个编号就可以找到这个字节进而访问这个字节,这个编号就是这个字节的地址

Char  一个字节

Int   四个字节

Int arr[5]  20字节

不管是多少个字节,每一个字节都有编号,那最终访问到这么多字节,你必须知道从那个编号开始的(首地址)以及你能访问的字节的个数,你就可以访问到这些字节

指针:地址就是指针

指针常量:内存的编号就是指针常量,因为不会发生改变

指针变量:用来存放内存编号的一个变量,可以被修改

 

我们平时说的指针默认指的是指针变量,也就是说直接说指针,而不说指针变量

指针就是地址,地址是组成内存的每一个字节的编号。

(一)指针的定义

&a是一个常量,p是一个变量,&a不能被改变,但是可以改变p的指向

 

Int a;

scanf(“%d”,&a);

printf(“%d”,a);

Int a = 10;

Int *p = &a;

P也是一个变量,不过是一个指针类型的变量,&a是一个常量,不过是一个指针常量。

指针就是地址,地址就是指针,一个指针不能同时指向两个空间,两个指针可以同时指向一片空间

通过 int *p = &a;这里的*是标识符,表示p是一个int*类型的变量,也就是指针变量

p的数据类型是int *,指向类型是int,所以通过上式可以得到 p = &a;

通过p = &a,想要通过指针p取a的值,需要用到取值运算符:*  *p = a;取p所指向的空间里面的内容。

Const修饰指针

Int const *p:const修饰的是*p(p所指向的空间里面的内容),这个内容变成只读,不能修改

Int * const p:const后面跟的是指针变量p,所以指针的指向变成只读,不能被更改

(二)指针的定义方式

数据类型 * 指针变量名 = 地址常量;

(三)指针的指向类型和数据类型

Int a = 10;

Int *p = &a;

指针的数据类型:去掉变量名  int *

指针的指向类型:去掉变量名和一个*  int

(四)指针的数据类型大小

指针的数据类型大小永远是固定的,64OS 是8个字节,在32OS 里面是4个字节,不会因为指向的数据类型改变,而改变自身的数据类型大小。

(五)*p和p

在指针里面 *的作用

  1. int *p;*的作用是标识符
  2. *p = a;*的作用是取值运算符,取了a空间里面的内容
  3. 分辨*的用法:标识符一般出现在定义的时候,会出现数据类型,取值运算符一般用在运算的时候,这时候不会出现数据类型。

(六)Const修饰指针

Int const *p:const 修饰的是*p,*p不能被改变,p的指向可以被改变

Int * const p:修饰的是p,p的指向不能被改变,改变的是*p的值

Int * const p    int const *p

*在const的左边还是右边

*在左边不能去修改p的指向,*在const的右边不能去修改值

左指,右数

(七)空指针和野指针

野指针:没有明确的指向的指针

 

怎样避免野指针?

让野指针先指向零号地址,变成空指针(指向零号地址),零号地址不能被操作

指针和字符串数组

Char Str[10];str[10] = “abcde”; 错的,不存在str[10]这个位置

Char Str[10];str = “abcde”; str是指针常量,常量不能赋值

Char *s;s = “abcde”; 正确,定义指针指向字符串,s+2输出cde

Char *s;*s = “abcde”;错误,再18.04里面char*s指向零号地址,零号地址不能被操作

Char str[10] = “abcde”;char *p = str; 正确 定义指针变量,将str(指针常量)赋值给变量

Char *s;s = “abcde”;s = “ab”; 正确,改变指针的指向

(八)二级指针

 

里面存放的是一级指针的地址

Int a = 10;   0x100

Int *p = &a;  0x104

Int **pp = &p; 0x108

Pp: 0x104

*pp: 0x100

**pp: 10

Int * const *pp:不能改变*pp,不能改变p的指向

Int ** const pp:不能改变pp,不能改变二级指针的指向

Int const **pp: 不能改**pp,也就是不能通过**pp去改变a的值

(1)二级指针的定义

数据类型  ** 变量名

(2)二级指针的数据类型和指向类型

Int a = 10;

Int *p = &a;

Int **q = &p;

二级指针的数据类型:int **

指向类型:int *

(3)const修饰二级指针

Int const **p:不能改变**p,也就是不能改变a的值,*p 和p可以改变

Int *const *p:

 

Int ** const p:不能改变p,也就是p永远指向a的地址,可以改变*p **p

(九)指针数组与数组指针

Int arr[3]

Int (*p)[3] = &arr;

输入:&((*p)[i])   (*p)[i]

(*P+i)      *(*p+i)

定义

 

数据类型 * 数组名[元素个数]

里面的元素全部是指针类型

(1)数组指针

数组指针和一维数组

数组指针的定义

数据类型 (*变量名)[一维数组的元素个数] = &数组名

(2)数组指针输出元素

(3)数组指针的大小和指向类型的大小

 

数组指针的运算

Int arr[3];

Int (*p)[3] = &arr;

p+1:地址增大的方向移动一个指向的数据类型(int [3])

p-1:地址减小的方向移动一个指向的数据类型(int [3])

p++:地址增大的方向移动一个指向的数据类型(int [3])

p--:地址减小的方向移动一个指向的数据类型(int [3])

P-q:无意义,给数组开辟空间是随机开辟的,并不能计算出两个数组之间差了多少个元素。

十、函数

函数是什么?

为了实现某些特定的功能的模块

char *strcat(char *dest, const char *src);

(一)自定义函数

返回值类型 函数名(数据类型 参数1 ,数据类型类型 参数2。。。。。)

参数的个数是根据自己的需要去定义的,可以有一个,也可以没有,也可以有多个

(二)形参和实参

形参和实参存放在栈区

(三)函数的返回值

函数的返回值类型如果不写,默认的返回值类型是int

如果函数不写return ,函数的返回值类型默认还是int

  1. 返回值:用来就接收函数所要实现的功能是否成功的标志,如果成功,可以用返回值类型定义的变量来操作这个函数所实现的功能,比如fopen打开一个文件流,socket,创建一个套接字。
  2. 函数名:起自己想要实现的功能
  3. 形参:如果不知道先不写,先完成想要实现的功能,然后实现的功能里面缺什么类型的变量,就给形参定义成什么。比如 input(),实现数组的输入,里面的函数需要arr[i],所以形参需要写成 int * arr。
  4. 直接的操作形参从而实现间接的操作实参

(四)函数的声明

地址传递

将x和y的地址传递给a和b,直接去操作x和y的地址,间接的去操作x和y的值。

数组指针永远指向一维数组

十一、结构体

Struct people

{

Char name[20];

Int age;

Float height;

}

Int   double float char

结构体是一个复合的数据类型,通常用在描述一个复杂的事物。

(一)访问结构体的成员

  1. 定义结构体变量
  2. 访问

一级指针和一维整型数组

一级指针永远指向一个普通变量的地址p = &a;,给指针变量不断的+1,就会变成一片连续的空间,连续的空间一般是数组,起名叫arr,此时a就变成数组的第一个元素arr[0],在数组里面第一个元素的地址&arr[0]和数组名arr是一样的,所以int *p = arr;此时arr和p可以相互替换。Arr++不存在,因为常量不能自加。

一级指针和字符串数组

Char str[10] = “abcde”;

Char * p = str;此时用p输出str会输出abcde。

P = &str[2];此时输出cde,因为此时相当于重定向,字符串的起始位置变成c

Char str = “abcde”;

Char str[10];str = abcde;

Char *s;*s = “abcde”;

Char *s;s = abcde;*s = b; abcde 放在常量区,常量区的内容不能被改变

数组指针和二维数组

数组指针始终指向一维数组arr,int (*p)[3] = &arr,然后对数组指针进行+1的操作,加出来的结果画图表示是一个二维数组arr1,所以一维数组arr变成了arr1的第一个元素arr[0],数组指针还是指向一维数组,int(*p)[3] = &arr[0],同时arr[0]是arr的首元素,所以arr = &arr[0],

Int (*p)[3] = arr;

输入:&p[i][j]   (p[i]+j)    (*(p+i)+j) 

输出:p[i][j]   *(p[i]+j)    *(*(p+i)+j) 

指针数组

就是一个数组,里面存放的是指针,也就是地址,可以放整型变量的地址,也可以放字符串,

也可以放字符串数组的名字

Char *str[3] = {str1,str2,str3}

输出字符串的时候用arr[0];

Int *arr[3] = {&a,&b,&b};

输出内部元素用 *arr[0]。

指针函数

本质上是一个函数,函数的返回值是一个指针。

Char * strcat(char * dest,const char * src)

函数指针

本质上是一个指针,指向了一个函数

Int add(int a,int b)

Int (*p)(int ,int ) = add

Malloc 和free

#include <stdlib.h>

void *malloc(size_t size);

Void * 空指针,可以将void *类型的指针强制类型转换成其他类型的指针

参数:所要申请的空间的大小

在堆区申请空间

       #include <string.h>

       void *memset(void *s, int c, size_t n);

参数1:空间的首地址

参数2:用什么字符来清楚

参数3:清除多大的空间

#include <stdlib.h>

void free(void *ptr);

参数1:所要释放的空间的首地址

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值