函数名在表达式中总是以函数指针的身份呈现,除了取地址运算符以及sizeof。
对于指针,尽最大的限度使用const保护它,无论是传递给函数,还是自己使用。
在编译器中会有两种NULL(每种环境都有唯一确定的NULL):
#define NULL 0
#define NULL ((void*)0)
有什么区别吗?看起来没什么区别都是0,只不过一个是常量,一个是地址为0的指针。
int* temp_int_1 = 0; //无警告
int* temp_int_2 = (void*)0; //无警告
int* temp_int_3 = 10; //出现警告
因为C语言规定当处理上下文的编译器发现常量0出现在指针赋值的语句中,它就作为指针使用,似乎很扯淡,可是却是如此。在字符数组的末尾使用NULL是绝对错误的!虽然它们的本质都是常量0,但由于位置不同所以含义也不同。
对于形参和实参而言两个关系紧密,可以这么理解总是实参将自己的一份拷贝传递给形参,这样形参便能安全的使用实参的值,但也带给我们一些麻烦,最经典的交换两数
void swap_v1(int* val_1, int* val_2)
{
int temp = *val_1;
*val_1 = *val_2;
*val_2 = *val_1;
}
这就是所谓的按址传递,实际上只是将外部指针(实参)的值做一个拷贝,传递给形参val_1与val_2,实际上我们使用:
#define SWAP_V2(a, b) (a += b, b = a - b, a -= b)
#define SWAP_V3(x, y) {x ^= y; y ^= x; x ^= y}
如果输入的两个参数本就指向同一块内存,会发生什么?
SWAP_V2(test_1, test_1);
printf("Now the test_1 is %d\n", test_1);
会输出Now the test_1 is 0
这是因为当修改test_1上面的值时,test_1上面的值会同时修改。
所以做交换的时候要判断两个参数是不是指向同一块内存。
static inline void swap_final(int* val_1, int* val_2)
{
if(val_1 == val_2)
return;
*val_1 ^= *val_2;
*val_2 ^= *val_1;
*val_1 ^= *val_2;
}
#define SWAP(x, y) \
do{ \
if(&x == &y) \
break; \
x ^= y; \
y ^= x; \
x ^= y; \
}while(0)
restrict,C语言中的一种类型限定符(Type Qualifiers),用于告诉编译器,对象已经被指针所引用,不能通过除该指针外所有其他直接或间接的方式修改该对象的内容。
要时刻记住,数组与指针是不同的东西。但是为什么下面代码是正确的?
int arr[10] = {10, 9, 8, 7};
int* parr = arr;
我们还是那句话,结合上下文,编译器推出 arr处于赋值操作符的右侧,默默的将他转换为对应类型的指针,而我们在使用arr时也总是将其当成是指向该数组内存块首位的指针。
在char数组中使用指针运算进行操作,提取不同类型的数据,或者是在不同类型数组中,使用char*指针抽取其中内容,才是显示指针运算的用途。但在使用不同类型指针操作内存块的时候需要注意,不要操作无意义的区域或者越界操作。