概述
C语言知识点补充
文章目录
- C语言知识点补充
- @[toc]
- **C库函数** `void *memset(void *s, int ch, size_t n)`
- **C库函数** `void mencpy(void *str1, const void *str2, size_t n)`
- **C库函数** `void *malloc(size_t size)` 动态内存分配
- **C库函数** `void free(void *ptr)` 释放内存
- **C运算符** `sizeof()` 判断变量或数据类型的字节大小。单位(byte)
- **C库函数** `strlen(const char *str)` 计算字符串 str 的长度,直到空结束字符,但不包括空结束字符
- **C库函数** `fflush()` 刷新流 stream 的输出缓冲区
- **C库函数** `scanf`, 从标准输入stdin读取格式化输入.
- **C库函数** `printf`, 发送格式化输出到标准输出 stdout.
- 格式字符
- 转义字符
- **C库函数** `char *strtok(char s[], const char *delim);`将字符串分割成一个个片段。
- **C库函数** `int strncmp(const char *str1, const char *str2, size_t n)`字符串比较函数
- **C库函数** `unsigned long int strtoul(const char *str, char **endptr, int base)`把输入的字符串转换成数字
- **C库函数** `double floor(double arg)`向下取整;`double ceil(double arg)`向上取整
- `?:`条件表达式. 如果条件为真?则值为X:否则值为Y
- `break`跳出当前循环(在switch中是结束掉switch循环)。
- **关键字**`static`
- **关键字**`const`
- **关键字**`struct` 结构体
- 结构体成员的`.`和`->`
- 结构体传递时注意点
- **函数指针** `int(*pFunc)(int, int)`
- 使用案例:
- **指针函数** `int *sub(int a, int b)`
- **数组指针**`int (*pArr)[10]`
- 使用案例:可以实现对一个多维数组进行逐行移动。
- **指针数组** `int *ArrP[10]`
- 使用案例:使用指针数组设计一个存放字符串的表。PS:一般在数组末尾加上一个NULL元素,来判断数组是否到了结尾。
- `#` 把宏参数变为一个字符串.
- `##` 为宏提供一种连接实际参数的手段.
- 实际运用 思路:用单独一个OSD2Image_Table.h文件封装起来,供客户等添加图片信息. (优点: 便捷、隔离)
- 链表与数组的区别
- 关于几个debug用到的宏
- ?操作符的结合性都是从右向左的
- 字符串的定义
- ???#pragma pack()
- 函数的参数之形参与实参
- 参数的传递
- 思考的例子
- 过程类型的函数 有return的函数
- 存储类型与存储区关系
- __attribute__
- section
文章目录
- C语言知识点补充
- @[toc]
- **C库函数** `void *memset(void *s, int ch, size_t n)`
- **C库函数** `void mencpy(void *str1, const void *str2, size_t n)`
- **C库函数** `void *malloc(size_t size)` 动态内存分配
- **C库函数** `void free(void *ptr)` 释放内存
- **C运算符** `sizeof()` 判断变量或数据类型的字节大小。单位(byte)
- **C库函数** `strlen(const char *str)` 计算字符串 str 的长度,直到空结束字符,但不包括空结束字符
- **C库函数** `fflush()` 刷新流 stream 的输出缓冲区
- **C库函数** `scanf`, 从标准输入stdin读取格式化输入.
- **C库函数** `printf`, 发送格式化输出到标准输出 stdout.
- 格式字符
- 转义字符
- **C库函数** `char *strtok(char s[], const char *delim);`将字符串分割成一个个片段。
- **C库函数** `int strncmp(const char *str1, const char *str2, size_t n)`字符串比较函数
- **C库函数** `unsigned long int strtoul(const char *str, char **endptr, int base)`把输入的字符串转换成数字
- **C库函数** `double floor(double arg)`向下取整;`double ceil(double arg)`向上取整
- `?:`条件表达式. 如果条件为真?则值为X:否则值为Y
- `break`跳出当前循环(在switch中是结束掉switch循环)。
- **关键字**`static`
- **关键字**`const`
- **关键字**`struct` 结构体
- 结构体成员的`.`和`->`
- 结构体传递时注意点
- **函数指针** `int(*pFunc)(int, int)`
- 使用案例:
- **指针函数** `int *sub(int a, int b)`
- **数组指针**`int (*pArr)[10]`
- 使用案例:可以实现对一个多维数组进行逐行移动。
- **指针数组** `int *ArrP[10]`
- 使用案例:使用指针数组设计一个存放字符串的表。PS:一般在数组末尾加上一个NULL元素,来判断数组是否到了结尾。
- `#` 把宏参数变为一个字符串.
- `##` 为宏提供一种连接实际参数的手段.
- 实际运用 思路:用单独一个OSD2Image_Table.h文件封装起来,供客户等添加图片信息. (优点: 便捷、隔离)
- 链表与数组的区别
- 关于几个debug用到的宏
- ?操作符的结合性都是从右向左的
- 字符串的定义
- ???#pragma pack()
- 函数的参数之形参与实参
- 参数的传递
- 思考的例子
- 过程类型的函数 有return的函数
- 存储类型与存储区关系
- __attribute__
- section
C库函数 void *memset(void *s, int ch, size_t n)
将s中当前位置后面的n个字节用 ch 替换并返回 s 。size_t n一般用sizeof()确定多少个字节。ch是赋给buffer的值。
C库函数 void mencpy(void *str1, const void *str2, size_t n)
从存储区str2复制n个字节到存储区str1。一般参数n用sizeof(str2)表示
C库函数 void *malloc(size_t size)
动态内存分配
返回值是一个指针,指向已经分配大小的内存,如果请求失败则返回NULL。
C库函数 void free(void *ptr)
释放内存
ptr–指针指向一个要释放内存的内存块
C运算符 sizeof()
判断变量或数据类型的字节大小。单位(byte)
C库函数 strlen(const char *str)
计算字符串 str 的长度,直到空结束字符,但不包括空结束字符
返回字符串的长度
C库函数 fflush()
刷新流 stream 的输出缓冲区
C库函数 scanf
, 从标准输入stdin读取格式化输入.
类型说明符
类型 合格输入 参数的类型 %a %A 读入一个浮点值 float * %c 单个字符:读取一个字符 char * %d 十进制整数:数字前面的 + 或 - 号是可选的。 int *
C库函数 printf
, 发送格式化输出到标准输出 stdout.
格式字符
格式字符 意义 d 以十进制形式输出带符号整数(正数不输出符号) s 输出字符串 x,X 以十六进制形式输出无符号整数
转义字符
转义字符 意义 b 退格(BS), 将当前位置移到前一列 f 换页(FF), 将当前位置移到下页开头 n 换行(LF), 将当前位置移到下一行开头 r 回车(CR), 将当前位置移到本行开头 t 水平制表(HT) v 垂直制表(VT) ? 输出? .用于书写连续多个问号时使用
printf("请输入三个字符:");
scanf("%c%c%c",&a,&b,&c);
printf("%d,%d,%dn",a,b,c);
C库函数 char *strtok(char s[], const char *delim);
将字符串分割成一个个片段。
参数s指向欲分割的字符串,参数delim则为分割字符串中包含的所有字符。当strtok()在参数s的字符串中发现参数delim中包含的分割字符时,则会将该字符改为 字符。在第一次调用时,strtok()必需给予参数s字符串,往后的调用则将参数s设置成NULL。每次调用成功则返回指向被分割出片段的指针。
#include <string.h>
#include <stdio.h>
int main () {
char str[80] = "This is - www.runoob.com - website";
const char s[2] = "-";
char *token;
token = strtok(str, s);//返回串中第一个s前的字符串
/* 继续获取其他的子字符串 */
while( token != NULL ) {
printf( "%sn", token );
token = strtok(NULL, s);//结果返回分割依据后面的字串
//如果,s为空值NULL,则函数保存的指针SAVE_PTR在下一次调用中将作为起始位
}
return(0);
}
C库函数 int strncmp(const char *str1, const char *str2, size_t n)
字符串比较函数
str1和str2比较,n为要比较的最大字符数。返回值< 0,str1 < str2; 返回值> 0,str1 > str2; 返回值= 0,str1 = str2 。
C库函数 unsigned long int strtoul(const char *str, char **endptr, int base)
把输入的字符串转换成数字
str:字符串的起始地址。endptr: 返回字符串有效数字的结尾地址(例1234fe56则返回f的地址)。base:转化基数 (2~36|0),用来代表str采用多少base进制。
C库函数 double floor(double arg)
向下取整;double ceil(double arg)
向上取整
?:
条件表达式. 如果条件为真?则值为X:否则值为Y
break
跳出当前循环(在switch中是结束掉switch循环)。
continue
跳过循环体中剩余的语句而强行执行下一次循环。
return
返回主调函数。
关键字static
- 修饰静态局部变量 存储于静态内存中的变量在程序的整个执行过程中将一直保留它们的值。
- 限制函数和数据定义的作用域 抽象数据类型(abstract data type)这个技巧也被称为黑盒.
关键字const
-
修饰变量,声明变量为只读特性,保护变量值以防被修改。此外还可以节约空间的目的,此变量保存到符号表中,无需读写内存,程序执行效率也会提高。
const int I = 5;//== int const I = 5
通常建议采用第一种声明 -
修饰数组。
-
修饰指针,修饰指针有两种形式,一种是用来限定指向的值不能被修改,另一种是限定指针不可更改。
/*记忆窍门 const在'*p'前,意思是修饰'*p'这个值,而这个'*p'的意思是指向的值 const在'p'前,意思是修饰'p'这个值,而这个'p'的意思是指针 */ const int *p1 = &i;//限定指向的值不可改变。 int *const p2 = &j;//限定指针不可改变。
-
修饰函数参数,const形参防止被函数内部修改。
关键字struct
结构体
结构体成员的.
和->
- 结构体成员的直接访问, 通过(.)操作符. 左操作数就是结构体变量的名字, 右操作数就是需要访问的成员的名字.
- 结构体成员的直接访问, 通过(->)操作符. 左操作数必须是一个指向结构的指针, 右操作数就是需要访问的成员的名字.
struct COMPLEX *cp;
通过(*cp).f调用里面的f成员. 但是很麻烦,所以C语言提供了(->)操作符, 所以变成了cp->f
结构体传递时注意点
尽量或者必须做到,传递一个指向结构体的指针而不是一个结构体
函数指针 int(*pFunc)(int, int)
指向函数的指针变量,在C编译时,每一个函数都有一个入口地址,那么指向这个函数的函数指针便是指向这个地址。函数指针主要有两个作用:用作调用函数和做函数的参数。
使用案例:
typedef int(*pFunc)(int,int);
pFunc pv(int,int);//pv 是一个函数指针int AddTwoNumb(int a,int b){return a+b;}
int main()
{
pv = AddTwoNumb;//pv存放AddTwoNumb函数的地址
int a,b;
sum = (*pv)(a,b);//sum = 函数AddTwoNumb return的值,若是不带参数的的函数则调用一次函数(调用方式:sum = (*pv)????
}
指针函数 int *sub(int a, int b)
其返回值是一个 int 类型的指针,是一个地址。
数组指针int (*pArr)[10]
下标引用的优先级是高于间接访问,但由于括号的优先级要高,所以先执行间接访问。
pArr是一个指向拥有10个整形元素的数组的指针。
使用案例:可以实现对一个多维数组进行逐行移动。
指针数组 int *ArrP[10]
下标引用的优先级是高于间接访问。
使用案例:使用指针数组设计一个存放字符串的表。PS:一般在数组末尾加上一个NULL元素,来判断数组是否到了结尾。
#
把宏参数变为一个字符串.
#define dprint(expr) printf(#expr"=%dn",expr);
...
int a=10,b=10;
dprint(a/b);
===============打印结果==================
a/b=1
##
为宏提供一种连接实际参数的手段.
#define cat(x,y) x##y
cat(var,3)将生成var123
实际运用 思路:用单独一个OSD2Image_Table.h文件封装起来,供客户等添加图片信息. (优点: 便捷、隔离)
fliename:OSD2Image_Table.h
//! Index SF Address Pos X Pos Y
OSD2IMGPOOL(OSD2IMAGE, 0, 0, 0)
OSD2IMGPOOL(PU_STSICON, 0x3000, 10, 0)
OSD2IMGPOOL(CAM1_STSICON, 0x3000, 430, 0)
#undef OSD2IMGPOOL//?好像加不加这个#undef也没什么影响
flienname:UI.h
typedef enum
{
#define OSD2IMGPOOL(idx,addr,posx,posy) OSD2IMG_##idx,
#include "OSD2Image_Table.h"
OSD2IMG_MAX
}UI_OSD2ImagePool_t;
Application Program
//调用
tOSD_GetOsdImgInfor(OSD2IMG_CAM1_STSICON);
解释:1.导入的图片按照Index, addr, position的规则来存放和读取.
2.通过一个enum枚举和##来把table中的格式规则, 变为更简便的格式.
OSD2IMGPOOL(PU_STSICON,0x3000,10,0)变成OSD2IMG_CAM1_STSICON
3.通过简化过后的格式调用, 找到图片存放的地方.
OSD2IMG_CAM1_STSICON = 1
链表与数组的区别
链表是通过节点把离散的数据链接成一个表,通过对节点的插入和删除操作从而实现对数据的存取。而数组是通过开辟一段连续的内存来存储数据这是数组和链表最大的区别。
数组的每个成员对应链表的结点,成员和结点的数据类型可以是标准的C类型或者是用户自定义的结构体。数组有起始地址和结束地址,而链表是一个圈,没有头和尾之分,但是为了方便节点的插入和删除操作会人为的规定一个根节点。
关于几个debug用到的宏
__VA_ARGE__
是一个可变参数的宏,在c99中新增的规范, 使用时在宏定义中参数列表的最后一个参数为省略号(…).##__VA_ARGE__
##起到的作用是把前面多余的,
去掉(ps:不管是几个参数都能正确打印).
__FILE__
宏在预编译时会替换成当前的源文件名
__LINE__
宏在预编译时会替换成当前的行号
__FUNCTION__
宏在预编译时会替换成当前的函数名称
?操作符的结合性都是从右向左的
字符串的定义
char site[7] = {'R', 'U', 'N', 'O', 'O', 'B', '