一、逗号运算符
在C语言中,多个表达式可以用逗号分开,其中用逗号分开的表达式的值分别结算,但整个表达式的值是最后一个表达式的值。
例如:
int a1, a2, b = 2,c = 7, d = 5;
a1 = (++b, c--, d++);
a2 = ++b, c--, d++;
其中第 2,3行就是使用了逗号运算符。
但是这两个表达式表达的意思不尽相同。
注意:
逗号运算的结合性是从左至右,完毕后整个表达式的值根据有无括号而不同。如果加上括号,则返回最后一个运算,没有就返回第一个。
例题中的计算结果a1 = 5,a2 = 4,其原理就是在计算a1的时候返回的是最后一个运算即d++(a1 = d++ = 5(先赋值再再进行加一操作)),但是此时b已经进行过了++b运算 值为3,c进行了c--运算 值为6);计算a2的时候返回的是第一个运算即++b(先加一再赋值),得a2值为4, 但是计算从左至右直到分号结束,则再进行c--操作,接着就是d++操作。
二、宏定义
概念
宏定义是C语言提供的三种预处理功能的其中一种(宏定义,文件包含,条件编译),宏定义和操作符的区别在于宏定义是替换,不做计算,也不做表达式求解,故又称宏代换、宏替换。
格式
#define 标识符 内容
其中标识符又可称为宏名, 一般采用的是大写
例:#define PI 3.1415926
注意
- 宏定义能提高程序的通用性和可读性,减少输入错误,便于修改
- 在编译前处理,即不尽兴语法检查
- 宏定义可以使用#undef命令终止其作用范围
- 宏定义允许嵌套
- 宏定义中不存在变量类型,也没有类型转换
- 宏定义中可以使用变量进行使用,调用的时候传参就好
- *宏定义只替换, 不做计算,也不做表达式求解
例子:
#define M(x,y,z) x*y+z
#include<stdio.h>
int main()
{
int a=1, b=2, c=3;
printf("%d\n",M(a+b,b+c,c+a));
}
只替换,不计算->a+b*b+c+c+a = 12;
而不是(a+b)*(b+c)+(c+a) = 19;
三、传参问题
当我们把一个指针作为参数传给一个函数的时候,其实只是把指针的副本传递了过去,也可以说传递指针是指针的按值传递。尽管它是一个指针,但如果我们在函数内部修改指针会出现问题,在方法里做修改只是修改指针的副本而不是指针本身,原来的指针还保留着原来的值。如果想用真正传递,可以使用二级指针或者指针的引用。
如果进行的是指针的引用,这个时候传入的不是指针的副本了,而是指针的本身,相当于取了个别的名字而本质未改变,改变了它的指向或者值,相应的全部都改变了。
例题:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
void getmemory(char*p) {
p=(char *) malloc(100);
strcpy(p,"hello world");
}
int main( ) {
char *str=NULL;
getmemory(str);
printf("%s\n",str);
free(str);
return 0;
}
ps:这个时候输出的就是null了,因为strcpy(p, "hello world")
改变的只是主函数中str的副本,而不是它本身,当函数结束后返回主函数,str依旧指向空。
四、数组指针
例题:
#include<stdio.h>
main(void)
{
int a[5]={1,2,3,4,5};
int *ptr=(int *)(&a+1);
printf("%d,%d",*(a+1),*(ptr-1));
}
分析
数组名就是一个指针,这样假设有个 p = int()(&a)这个时候p就是指向a这个一维数组的指针,即数组指针, 而这个时候p的步长就是a数组的长度,即(p+1)将跨过n个整型数据的长度; ptr也是一个数组指针,不过进行了加一操作,即跳出了数组a的范围,进行(ptr-1)操作则回到数组,此时指向的是a数组的末尾元素即a[4];所以输出的结果是 2, 5;