C语言学习笔记
时间:2023-10-18 11:07:01
2022.7.26号更新
1、
EXAMPLE_DEVICE_NAME是字符串,默认类型char*类型
而P_LEN是unsigned char*正确的方法如下:
2、‘\0和0和0和0的区别
首先对比一下‘’\0和0的区别。有一个共同点,它们都是字符。在c语言中,字符是相应的ASCII存储代码,一个字符占据一个字节。请看第一个ASCII代码,对是0,对应的字符是(Null),其实就是 ‘\即空字符。判断字符串是否结束的标志取决于它是否遇到‘\0’,如果遇到‘\0,表示字符串结束。字符0对应ASCII码是 48,48对应的十六进制数就是0x30。例如,如果你想将8转换为字符8,你可以在句子中这样写 了,“ 8 ‘0’”。这里的8是数字。字符0和数字0的区别:前者是字符常量,后者是整形手术常量,其含义与计算机中的存储方式完全不同。但字符常量 在程序中可以像整数一样参与相关操作。例如:9-3;哈哈,是不是又一村柳暗花明?
接下来我们来比较一下0和0的区别。首先,0是字符串常量,字符串常量是由一对双引号包含的字符序列。例如:“CHINA”,“I LOVE YOU123等都是合法字符串常量。0是字符常量,字符串常量和字符常量不同。1:单引号包括字符常量;双引号包括字符串常量。2:字符常量只能是单个字符;字符串常量可以包含一个或多个字符。
2022.7.23号更新
1、u8 *cmd="AT";
printf("%s",cmd);//可输出AT
2、while(1)
{
break;
}//break最近一个可以退出while循环。
3、&&与&最大的区别:&&是逻辑和,只会返回0和1。
4、
do_crc(&p_data->DEVNO,7);//必须添加&符号
5、
mymalloc函数在malloc.h头文件中有定义,SRAMIN是内部内存池,SRAMEX是外部内存池。
在内存中定义动态堆区,并将堆空间的第一个地址给指针p。一般开辟这段内存是存放临时的数据。
6、strstr函数的概念
strstr(str1,str2) 函数用于判断字符串str2是否是str1的子串。如果是,函数返回 str1字符串从 str第一次出现的位置开始到 str1结尾的字符串;否则,返回NULL。
1、sizeof()和strlen()函数有什么区别?
int main()
{
char *p = "hello";
char q[] = "hello";
char s[10] = "hello";
printf("%d, %d, %d\n", sizeof(p), sizeof(*p), sizeof(q), sizeof(s));
return 0;
}
输出结果为:4, 1, 6, 10
p是指针,sizeof(p)得到的是指针占用的字节数,所以sizeof(p)结果为4,p是指向“hello”的指针,*p是“hello第一个字符h,是char类型,sizeof(*p)结果是1,char q[]没有指定数组的大小,根据hello”来确定,“hello包括空字符\0有6个字节,所以sizeof(q)结果为6。char s[10]指定数组大小,包括10个char所以sizeof(s)结果为10。
以下句子是错误的:
char q[5] = "hello"; //"hello"是const char[6]类型不能用于初始化char[5]实体类型。
总之,对于指针,sizeof对于数组来说,返回该指针所占的空间通常是4个字节,sizeof返回这个数组中所有元素的总空间大小。char q[]占用空间的大小取决于指向字符串或字符数组的大小,char q[10]占用空间的大小由指定的数组大小决定。
char *p = "hello";
char q[] = "hello";
char s[10] = "hello";
strlen(p), strlen(q), strlen[s]返回结果为5,strlen(p)参数为字符指针(char *),返回字符串的长度不包括‘\0‘。
2、extern的用法
已经在lcd.c下面包含了文件lcdfont.h所以在文件中main函数包含这个头文件会显示重复定义,复定义main还需要使用函数lcdfont.h所以可以有中数组extern这个关键字。
假设b.c下面定义了文件 int b;这句话,所以在a.c如果您想在文件中使用此变量,可以直接使用1)extern int b,但不推荐这种方法;
- 也可以在b.h在头文件中声明extern int b,直接调用头部文件。因为B文件可能是你的同事写的,为了更好地协调,你的同事声明B文件的整体变量是外部变量,方便你使用。
在a.c中定义了extern int b;然后当编译时就会生成a.o文件,但不会找到变量B在哪里,而是使用它symbol同时标记b.c文件也会编译,b.c变量定义在文件中b,当两个文件都被编译时,它们将被链接起来,以找到b变量。
3.用宏定义写一个函数
4.输出字符串的格式为%x。
5、sprintf函数的用法
sprintf其功能是将格式化字符串输出到目的字符串中,printf将格式化字符串输出到屏幕上。
但是在keil中不能省略char*类型
6、
注:结构成员不能赋予初值。
7、
8、volatile使用关键词
一般来说,硬件寄存器需要使用volatile外设中的寄存器可以每次访问关键字,而不是Cache。
9、c语言中堆栈指针的位置,C语言及ARM中堆栈指针SP设置的理解与总结
10、\r\n和\n\r是不一样的
在printf函数中打印\n\r跟没打印一样,打印\r\n才会回车和换行。
11、printf函数如果将一个浮点型的数据输出%d时,数据就会让人看不懂
12、
WriteData是一个数组的名称,也就是一个数组的首地址。
13、
BaseType_t RET;
RET=xTaskCreate(task2,"Task2",100,NULL,1,&Task2_Handle);
上面这种写法就没问题
BaseType_t RET=xTaskCreate(task2,"Task2",100,NULL,1,&Task2_Handle);
这种写法就会报错。
14、定义数据类型是不占用内存空间的
下面这条语句才会占用内存空间,只有定义了变量才会占用内存空间
15、结构体变量占用的内存空间
占用8个字节。
占用104个字节。
占用8个字节
CPU既可以通过偶地址也可以奇地址实现对单个字节的变量进行写,如果是对四个字节的变量进行写就需要从偶地址开始,并且是四个字节为一个整体进行访问(因为是32位处理器,这样访问效率最高)。
占用8个字节。
占用了104个字节
16、变量赋值需要注意的问题
全局变量就会按单个字节分配char类型的变量。
说明如果是局部变量的话,char类型的变量就会按四字节来分配地址,并且是按地址从高到低分配内存,只有栈才会这样分配。
17、
在main函数的下面定义了一个函数
在serial.c文件下面定义了一个函数
结果打印出来的是main.c。说明函数名称相同的话优先执行本地文件。如果把static关键字去掉的话就会报错了,因为会显示重复定义函数。
18、结构体多种常见写法
19、结构体指针和函数指针
注意:结构体中的classmate变量所占的空间并不清楚,而且会无限套娃,因此不可以使用
正确做法如下:
结构体指针
int * add(int a,int b);
这个函数有两种意思,一种是返回值是int *类型,一种是定义了函数指针*add。
为了区分两种意思,应该进行括号分割,当表示返回值是int*类型时,(int * )add(int a,int b);当表示定义了函数指针时,int (* add)(int a,int b);
int (* add)(int a,int b);跟int * add;没有什么差别。int (* add)(int a,int b);并不是一个函数,而是一个变量,这个变量是一个函数指针。
错误写法如下
Ifdef即便判断到LCDA为0也会执行,因为有定义。
执行的是LCD_A()
20、Typedef
typedef 1 A;是错误的
但是#define A 1就是正确的
Typedef int A;
A i;
就是对的
因为typedef的第二个参数只能是类型,因为typedef本来字面意思就是定义类型的。
左边的结构体可以由右边两个结构体组合而成。Lcd_operation是前面红框的别名,同理下面的结构体指针类型也是。
21、链表
用一个while(Head)就很巧妙,因为最后一个节点的NEXT是指向NULL。
链表改进
尾部增添成员
删除任意元素(有可能要删除的元素并没有)
从小到大排列
通用链表
这种是之前的,采用的是上一个节点的next指向下一个节点的首元素的地址。
改正如下:
它是通过下面这种方法求出偏移地址
将last->next转化为char*类型进行相减可以保证是按存储单元为字节数进行相减的。
21、通用链表的三种实现方法
得到了node结构体的地址就得到了person结构体的首地址。
传入的是node_t的指针,由于这个指针是struct person下的node的成员,因此类型是struct person, 成员是node。
双向链表
22、FreeRTOS链表代码分析
uxNumberOfItems表示有多少个元素
pxIndex指向当前在用的Item,被用来遍历链表。
pvOwner是包含Item的结构体
pxContainer:链表
Item初始化
增加一个元素到尾部
加入一个新元素必须加入到Index指向的item之前,也就是插入到Index->pxPrevious该item的后面。
排序item
22、ARM架构与汇编指令
23、全局变量的初始化
在bin或者HEX文件里面有代码段和数据段,有值的全局变量就是保存在数据段里的,当烧录到Falsh里面时也是分为代码段和数据段,当程序运行时就会把Flash里面的数据段原封不动的拷贝到RAM中。
ZI段是RAM里面的一段内存空间,相当于menset函数,将未初始化或者初始化为0的全局变量的值都初始化为0。
等到有值的全局变量以及初始化为0、未初始化的全局变量都存放好之后就开始调用main函数了。
Flash里面有代码段和数据段,当程序运行时,数据段会通过类似于mencpy函数的方式重定义到RAM中的Data段,这段空间用于存放有初值的全局变量;同时RAM中也划分出来ZI段,这段空间用于存放初值为0或者无初值的全局变量;接着SP指针会指向RAM中一段空闲的空间用于作为堆栈空间,最后main函数才开始调用。
栈的引用