1.宏的副作用(精髓在于直接替换)
#define mulitiply(a, b) a*b //带参数的宏定义
multiply(1+2,2); 直接替换后为: 1+2 * 2 实际想要的效果是(1+2)*2
#define multiply(a, b) ((a)*(b)) //理想的写法,避免上面的错误
#define hash(str, sz, rst) do{unsigned int n=0; n=xxx; rst=n%sz;} while(0)
hash("hello",7,n); //这个n和unsigned int n=0冲突,小作用域的起作用
宏定义内部使用不同的命名风格
#define max(a,b) ((a)>(b)?(a):(b))
int c=max(a,b++); //不要用++,--来使用宏定义
#define max(a,b) ({int _x=(a),_y=(b); _x>_y?_x:_y}) //保证传入宏的实参在内部只执行一次,限定了int,不通用
宏定义中定义临时变量时候要用大括号括起来
宏定义要返回值的话,最外层还要再用小括号括起来
内联函数其实就是宏定义的一种取代,避免了宏定义的副作用。内联函数不能单独声明,声明和实现写在一起。
*********膜拜大牛:https://onevcat.com/2014/01/black-magic-in-macro/****************
#define NSlog(format, ...) do{
fprintf(stderr,"<%s : %d> %s\n",
[[[NSString stringWithUTF8Sting:_FILE_] lastPathComponent] UTF8String],
_LINE_, _func_);
(NSlog)((format), ##_VA_ARGS_);
fprintf(stderr, "-----\n");
} while(0)
分析:
函数宏,参数:... (可变参数),第一个format被单独处理,剩下的参数作为整体处理。
do-while(0) 只执行一次,何不去掉?出现问题:
if(err)
NSlog(@"Oops,error happened"); 展开:连缩进都保持一样
if(err)
fprintf((stderr,"<%s:%d>%s\n",[[[NSSTring stringWithUTF8String:_FILE_]lastPathComponent]UTF8String] //输出
(NSlog)((format), ##_VA_ARGS_);
fprintf(stderr,"----\n");
if后的单条执行语句不加大括号也没问题,这是错误的认识。宏展开后,一个整体因为if语句而被分割开了。
因为没有大括号,那加上大括号:
#define NSlog(format, ...) { }
调用的时候:
if(err)
NSLog(@"Oops,error happened"); 展开是这样: { }; 最后会多个分号, 单个可以编译通过,但是如果
if(err)
NSLog(@"Oops,error happened");
else
dosomething 就会出错,展开是 if() { }; else dosomething 肯定出错,else前面多了分号。
所以用do while(0); 吃掉了那个分号,像这样
if(err)
do{
}while(0);
else
something;
[[[NSString stringWithUTF8Sting:_FILE_] lastPathComponent] UTF8String],_LINE_, _func_对应于fprintf的
%s,%d,%s. _FILE_, _LINE_, _func_是预定义宏,编译器指定的。
(NSlog)((format), ##_VA_ARGS_); 前后双下杠一般都是预定义宏,_VA_ARGS_表示...中剩余的参数。
##意思是前后两项合并,将前面的格式化字符串和后面的参数列表合并。
#define NSLogRect(rect) NSLog(@"%s x:%.4f, y:%.4f, w:%.4f, h:%.4f", #rect, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height)
#define NSLogSize(size) NSLog(@"%s w:%.4f, h:%.4f", #size, size.width, size.height)
#define NSLogPoint(point) NSLog(@"%s x:%.4f, y:%.4f", #point, point.x, point.y)
******************************************************
第一次见这种用法,编译器不会报错。。。。
char* fun()
{return "nihao";}
******************************************************
c语言4区模型:
1栈区(stack):编译器自动分配释放,局部变量,形参等
2堆区(heap):程序员分配释放
3数据区:静态区(全局变量,静态变量)+常量区(常量值)
4代码区:存放函数代码的二进制
c++中类的存储:
成员变量(静态)-静态数据区
成员变量(一般)-存储于对象中,字节对齐
成员函数-代码区
******************************************************
d_storage=(T*)adsCalloc(memsize*sizeof(T)+LVEC_EXTRAL_SIZE_FOR_SIZE,1);
d_storage=(T*)(char*)d_storage+LVEC_EXTRAL_SIZE_FOR_SIZE;
思维僵化:
adsCalloc只是分配了一段内存,而且memsize*sizeof(T)+LVEC_EXTRAL_SIZE_FOR_SIZE只是表示多少个字节
并不是说LVEC_EXTRAL_SIZE_FOR_SIZE一定放在最后面|TTTTT|LVEC_EXTRAL_SIZE_FOR_SIZE|
也可以|LVEC_EXTRAL_SIZE_FOR_SIZE|TTTT|,总之这块内存的长度是不变的,LVEC_EXTRAL_SIZE_FOR_SIZE可以用来存储比如后面T的个数之类的冗余信息。
*******************************************************
循环中让某一个函数只执行一次
bool forone=false;
while(1){
if(forone){
fun();
forone=true;
}
}
*********************************************************
函数指针(指针):int (*func)(int,int); 指针函数(函数):int* func(int,int); |*|<|()| 优先级
函数指针作为指针函数的返回值:int (*func(int))(int,int)
func(int)-函数 *func(int)-函数返回值为指针 也就是int (*)(int,int)是一个指向函数的指针 *-----*func(int)
typedef int (*pf)(int,int); pf func(int);
int *p; //这种写法比较好,p带有*则表示p是一个指针
int (*p)(int); //p前面有*,所以是指针,又后面是(int)表示是个函数,所以p表示指向函数的指针
int func(int);---------int (*p)(int); func----*p func是函数,p是指针 p是指向函数的指针
int (*p)[100]; //p指向一个数组,该数组含有100个整型
int arr[100];------int (*p)[100]; arr是数组,p是指针,p是指向数组的指针
文件处理程序,菜单按钮选择相应的操作(打开文件,读文件,写文件,关闭文件,函数形式相同)
void open(); void read(); void write(); void close();
定义函数指针,把上面4中操作放入一个数组中:typedef void (*PF)();
PF file_options[]={&open, &read, &write, &close};
int *(* (*fp)(int))[10] 解析:
*fp-fp是指针, (*fp)(int)-fp是函数指针,等价temp=(*fp)(int) >>>>碰到函数指针后,再外层就是该函数返回值<<<<
int *(* temp)[10] 解析:
*temp-temp是指针,(*temp)[10]-temp指向一个数组,数组元素是int*
总体:fp是指向函数的指针,该函数返回的是一个指向数组的指针,数组有10个int*的元素。
************************感谢csdn博主porscheyin大神********************
int* ptr, ptr2; //定义了ptr指针,ptr2是int,避免歧义,推荐int *ptr, ptr2;
1.NULL,空指针常量,int *p=NULL; char *p=0;
2.取变量地址,int i=3; int *ip=&i;
3.>>指针常量,long *p=(long)0xffff ffff ffff fff0; (64位,long是8字节)
4.数组名,char arr[]={"sdsasd"}; char *cp=arr;
5.>>另一个指针的地址,int t=3; int *tp=&t; int *tpp=&tp;
6.>>字符串常量,char *cp="nihao";
void* 可以接收其他任意指针赋值(函数指针只能接受函数地址,不接受void*);
void *all=NULL; int *ip=NULL; all=ip;
反过来:ip=(int*)all;
*************************感谢csdn博主porscheyin大神********************
T型指针与一个整数n相加,在内存上移动字节数为sizeof(T)*n.
数组名是一个常量指针,指针自身的值不可以改变,如arr++(实质是arr=arr+1),arr+=3;都是违法的
sizeof一个数组名返回的是:整个数组的大小,元素个数*元素大小
int arr[10]; sizeof(arr)=10*4=40字节,但是
int *arrp=arr; sizeof(arrp)=4字节,一个指针的大小
假若要访问二维数组matrix中第1行第1列(注意数组下标从0开始)的元素可以有以下的几种方式(i为int型变量):
通过数组名引用 通过指针p的引用 通过指针column_p的引用
i = matrix [0][0]; i = *(*(p+0)+0); column_p = matrix[0];
i = *(matrix [0]+0); i = *(p[0] + 0); i = *(column_p+0);
i = *(*(matrix+0)+0); i = (*(p + 0))[0]; i = column_p[0];
0可以省略。
printf("%p\n", &matrix); 对应的指针操作:无
printf("%p\n", matrix); 对应的指针操作:printf("%p\n", p);
printf("%p\n",&matrix[0]); 对应的指针操作:printf("%p\n", p);
printf("%p\n",matrix[0]); 对应的指针操作:printf("%p\n", column_p);
printf("%p\n",&matrix[0][0]); 对应的指针操作:printf("%p\n", column_p);
输出的结果是一样的,但是类型不一样
&matrix: 对二维数组名取地址,返回一个指向二维数组的指针;
matrix: 二维数组名会被转换为指向第一行(第一个数组)的指针,与&matrix[0]等价;
&matrix[0]:对第一个一维数组的数组名取地址,返回一个指向一维数组的指针;
matrix[0]: 二维数组中第一个一维数组的数组名,与&matrix[0][0]是等价的;
&matrix[0][0]:对第一行第一列元素取地址,返回一个指向整型元素的指针。
******************************************************************************************************
字符串常量除了
1.作为 &操作符的操作数;
2.作为sizeof操作符的操作数;
3.作为字符数组的初始化值
会被默认转化成由一个指针所指向的字符数组。比如一个字符串“abcdefg”.printf("%c\n",*"abcdefg"); //输出a
printf("%c\n", *("abcdefg"+ 1)); //输出b
printf("%c\n","abcdefg"[5]); //输出f
char arr[]="abcd"; //初始化一个字符数组的元素,arr是一个字符数组,把字符串常量赋值到数组中,arr[0]='q';是对的,实质是一个字符数组,而不是字符串常量。char arr2[]="abcd";arr和arr2的地址是不同的
char* p="abcd"; //p是一个字符串常量,不可以通过p改变字符串常量,p[0]='e';是错的,实质是字符串常量。char* p2="abcd";p和p2的地址是相同的,用两个指针同时指向一个字符常量。