[原创]C语言高级用法-学习笔记

2020-04-17 04:54

1. #的作用

#是将其后的变量直接转换为字符串 void WriteLog(arg) {

printf(\}

2. ##的作用

##的作用是连接两个变量 如

#define combine_converse_str(x,y) x##y

int Err; int Num;

printf(\结果为:ErrNum

再如: int a=1; int b=2; int ab=3;

printf(\

结果为: 3

后面那句相当于printf(\

3. do{ }while(0)作用

1,空的宏定义避免warning: #define foo() do{}while(0)

2,存在一个独立的block,可以用来进行变量定义,进行比较复杂的实现。

3,用在宏定义上并且当宏定义需要定义成多条语句的组合时,可以保证这几条语句是一个整体的,并且可以消除使用这个宏定义后添加\所带来的报错,例如: #define aaa(x,y) \\ do{ \\

int a=0; \\ int b=0; \\ 函数1(x); \\ 函数2(y); \\ }while(0)

调用aaa(x,y); 时不会报错并且如果使用: if (m)

aaa(1,2); else

aaa(3,4);

时运行也不会使某些语句没有被运行到。

4. 数组名的使用

A. 数组名作为函数参数:数组名用在某个函数A的参数中时,处于函数传递效率原因,会

被强制转换成了指针,此后在函数A内就完全是一个值等于对应数组首地址的指针变量,可自加自减等 注意!只有在作为函数参数的情况下才会将数组名强制转换成指针,其他的都不会转换。 另:数组名作为函数参数传递时,函数声明的写法有多种 int aaa(char x[])

int aaa(char x[1]) int aaa(char x[100]) int aaa(char *x)

作为函数参数时的参数声明也和普通的数组定义一样要合法,比如不能 int aaa(char x[0]),因为定义一个数组也不能用 char x[0]来定义,编译器在检查参数的声明合法后,如果发现参数是数组,就会强制转换成指针,所以int aaa(char x[1])和int aaa(char x[100])的结果是一样的。

B. 数组名用在sizeof上:结果返回的是整个数组所占空间的大小,而不是一个指针的长度 C. 数组名与&和*:a与&a与&a[0]的值都相等,a是数组名,&a是整个数组地址,&a[0]

是数组首元素的地址,他们都相等

int a[5]={1,2,3,4,5};

printf(\

printf(\ printf(\

printf(\ printf(\printf(\

printf(\printf(\结果: a=12ff34 &a=12ff34

*&a=12ff34 ---*与&消掉,*&a=a=0x12ff34 &a[0]=12ff34

*&a[0]=1 ---*与&消掉,*&a[0]=a[0]=1

*(&a[0])=1 ---*与&消掉,*(&a[0])=*&a[0]=a[0]=1

*((int *)(&a))=1 ---*与&之间有个强制类型转换(int *),无法直接消掉,所以按照括号次序来运算(int *)(&a)=0x12ff34, *((int *)(&a))=*(0x12ff34)=1

*(*(&a))=1 ---*与&消掉,*(*(&a))=*a=1

D. 指针数组:

定义:基类型 *数组名[]

使用:像普通的数组一样使用,数组名代表首地址,数组名[0]表示第一个元素的内容,以此类推。

常见的是字符串数组,例如: char *Names[]= {

Bill, Sam, Jim };

实际内存中保存的就是

即首地址0x12ff0c{0x00423018,0x0042f2f4,0042201c},其中0x00423018地址所保存的就是”Bill”,所以数组名Name=0x12ff0c, &Name=0x12ff0c,*Name=0x00423018,**Name=0x42

printf(\ printf(\ printf(\

printf(\ printf(\printf(\printf(\printf(\printf(\printf(\

printf(\ printf(\结果是

Name=&Name=*&Name=&Name[0]=0x12ff0c

*Name=Name[0]=*&Name[0]=*(&Name[0])=(*((int *)(&Name)))=(*(*(&Name)))=0x00423018 **Name=*Name[0]=0x42

注意!指针是一级,数组是又一级,所以指针数组是二级指针,定义对应的指针变量要用二级指针,比如 int **p=Name; 不能直接用int *p=Name

5. 常量的定义和指针常量的定义及使用:

1.常量的定义:

const int a=10; //在其他地方不允许修改a的值,否则会编译不通过. 也可以写成 int const a=10; //一样的 2.指针常量的定义和使用:

有3种定义: const int *pi; 和 int const *pi; 以及 int * const pi; 1)前两种情况一样的,没有区别。

1) 如果const 修饰在*pi前(前2种情况)则不能改的是*pi(即不能 类似这样:*pi=50;赋值)而不是指pi.

2) 如果const 是直接写在pi前(后一种情况)则pi不能改(即不能类似 这样:pi=&i;赋值)。

6. 函数参数传递的4种类型:

1.值传递

void Exchg1(int x, int y) {

int tmp; tmp = x; x = y; y = tmp;

printf(\ }

main() {

int a = 4,b = 6; Exchg1(a, b);

printf(\ return(0); }

2.地址传递

void Exchg2(int *px, int *py) {

int tmp = *px; *px = *py;

*py = tmp;

printf(\ }

main() {

int a = 4; int b = 6;

Exchg2(&a, &b);

printf(\ return(0); }

3.引用传递

void Exchg3(int &x, int &y) {

int tmp = x; x = y; y = tmp;

printf(\ }

main() {

int a = 4; int b = 6; Exchg3(a, b);

printf(\ return(0); }

4.变长参数传递:使用省略号…指定参数表 使用的宏及其定义(x86中): #define va_start _crt_va_start #define va_arg _crt_va_arg #define va_end _crt_va_end

typedef char * va_list;

#define _ADDRESSOF(v) ( &(v) )

#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) ) #define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) ) #define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) #define _crt_va_end(ap) ( ap = (va_list)0 )

实例:

#include \


[原创]C语言高级用法-学习笔记.doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:计算机化系统管理规程

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: