C语言编程

C语言编程

1.sscanf()

sscanf()与scanf()类似,都是用于输入的,只是后者以键盘(stdin)为输入源,前者以固定字符串为输入源。

头文件:#include<stdio.h>

格式:int sscanf(const char *buffer,const char *format,[argument ]...);

举例:

char *p = "123";

int val = 0;

sscanf(p,"%d",&val);

则val == 123。

2.零长度数组

在嵌入式开发尤其是linux kernel中常用到零长度数组,可以用零长度数组成员作为可变长度数组的占位符。如以下定义:

typedef struct my_data
{
	int val;
	int len;
	char var[0];//零长度数组成员
}data_t;

其中的成员var[0]为零长度数组,由于它的长度为零,即不占存储空间,因此以上结构体所占用的空间sizeof( struct my_data) == sizeof(val+len)。那么,var[0]成员有什么用途呢?其功能就是,我们可以定义可变长度的数组,并通过var[i]访问该结构体中成员len之后的第i个数据。

如下所示:

#define LEN		10
data_t *test = malloc(sizeof(data_t)+LEN);
test->var[8] = 5;//访问另外LEN内的数据

3.extern修饰函数

在头文件中声明函数或者在C文件中定义函数时,加不加extern都是相同的,因为在这两种情况下,函数默认就是extern的。

4.数组名不等于函数指针

比如, 我们可以通过sizeof()计算数组的长度:
char  p[100];
sizeof(p) = 100;
char *p;
sizeof(p)=4;

因此,注意数组名与函数指针之间的差异。

5.计算结构体中元素的偏移

如定义了一个结构体

struct OffsetTest
{
	char a;	//offset->0
	char b;	//offset->1
	char c;	//offset->2
	char d;	//offset->3
	int e;	//offset->4
	int f;	//offset->8
};
则可以通过如下定义的宏计算结构体中任意一个元素的相对偏移:

#define OFFSET_OF(struct_name, field)   					((int)&((struct_name *)0)->field)
而计算结构体的大小可以直接用sizeof()运算符计算。

6.itoa() 和atoi()函数

itoa():将整型值转换为字符串,atoi()则实现相反的操作。

在不支持这两个库函数的系统中,可以自己编写类似功能的函数。如下所示:

int my_atoi(char *str)
{
	int i = 0,ret = 0;	
	ret = (*str++ - '0');
	while(*str)
	{
		ret = ret*10 + (*str - '0');
		str++;
	}
	return ret;
}

7.循环移位操作

#define ROTATE_LEFT(x,n) ((x) << (n)) | ((x) >> (sizeof(x)*8 - (n)))
#define ROTATE_RIGHT(x,n) ((x) >> (n)) | ((x) << (sizeof(x)*8 - (n)))

8.strcpy()、 strncpy()与strlcpy()

A.strcpy()
strcpy()在拷贝字符串时,以"\0"为结束标志,如果源字符串不以“\0”结尾,则程序会陷入死循环。而如果目的地址的存储空间比源字符串长度小的话,还会造成内存溢出。因此,strcpy()的使用存在一定的安全问题,使用时要谨慎。
B.strncpy()
strncpy()相对于strcpy()而言相对安全,但当源字符串中字符数量(不含末尾的0)于目的空间大小相等时,不能保证在目的地址后补0,因此,使用strncpy()时标准的做法是在拷贝完成后,在目的字符串的末尾填充0。
C.strlcpy()
strlcpy()不是ANSI C中的标准内容,但是linux中经常用到。这个函数能够保证最多拷贝目的空间大小减去一个字符,并会在末尾自动补0,因此更安全。

9.求整数N的阶乘(n!)

unsigned int factorial(unsigned int n)
{
	unsigned int result = 0;
	if(n >= 2)
	{
		return n*factorial(n-1);
	}
	return 1;	
}

10.逗号的用法

A.逗号作为逗号运算符,构成逗号表达式,又称顺序求值运算符
此种情况,从左到右依次求解各个表达式的值,整个逗号表达式的值最终等于最右边的表达式的值,如下:
	int a = 1,b = 2;
	printf("Result = %d!\n",(a = b+a,a));
如,上述代码执行的结果为3。
B.逗号作为分隔符
在printf函数中,对参数的计算顺序是从右往左的。
如下:
	int a = 1,b = 2;
	printf("Result = %d,%d,%d,%d!\n",a,b,a += b,b += a);
上述代码的运行结果为4,3,4,3。

11.宏中定义局部变量以及通过宏函数获取返回值

#define get_val(n)			\
({					\
	unsigned int v;			\
	if (n > 100)			\
		v = 1;			\
	else				\
		v = 0;			\
	v;				\
})

12.可变个数参数的宏函数

#define LOG(fmt,arg...)				printf(fmt,##arg)

13.fflush()和fsync()

int fflush(FILE *stream):只能将数据刷到文件系统的缓存中,并没有真正写到存储介质里。
 int fsync(int fd):才会把数据刷新到存储介质里。
但是因为fsync()的参数为文件描述符,当通过fopen()打开文件时,需要将文件流指针转换为文件描述符,可以通过fileno()函数进行转换。

14.内存地址对齐

在编程过程中,或者需要对程序进行优化时,经常需要用到地址须按字对齐的变量或数组等,如下面语句中的关键字__align(4) 用于使定义的数组的首地址按4字节对齐:

__align(4) uint8_t DataBuf[2048];


15.头文件的应用

static CommandInfo commands[] = {
#include "my_commands.h"
};

16.指针

A.一个指向函数的指针,该函数有一个整型参数并且返回值为整型?
int (*p)(int);
B.一个指向有10个整形数数组的指针?
int (*p)[10];
C.一个有10个指针的数组,该指针指向一个函数,该函数有一个整形参数并返回一个整形数?
int (*(ptr[10]))(int);











































评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值