1. 宏是代码的替换,中间不进行任何数据计算的操作
2. 能加括号就加括号,不要啬小括号
带参宏与函数的区别:
1. 函数有参数类型、返回值、调用的概念
2. 带参宏只是代码的替换
3. 带参宏会让程序代码体积增大
4. 函数不会让程序代码体积增大
5. 函数传参会占用资源开销,增大程序运行时间
6. 带参宏没有传参调用的过程,程序运行速度更快
带参宏:
用于封装比较简单的模块代码
举例:用带参宏判断最小值、用带参宏输出
#include
#define MINNUM(X,Y) ((X) < (Y) ? (X) : (Y))
#define PRINTNUM(x,y,z) do{ \
printf("x = %d\n",x); \
printf("y = %d\n",y); \
printf("z = %d\n",z); \
}while(0)
int main(void)
{
int Num1 = 0;
int Num2 = 0;
int MinNum = 0;
scanf("%d%d", &Num1, &Num2);
MinNum = MINNUM(Num1,Num2);
printf("MinNum = %d\n",MinNum);
PRINTNUM(Num1,Num2,MinNum);
return 0;
}
1. 代码更加简洁高效
2. 指针可以直接访问内存
3. 指针可以操作硬件
1. 地址:用来区分内存中不同字节的编号
2. 指针:指针就是地址,地址就是指针,指针多了指向的概念
3. 指针变量:是一个变量,变量里面存放了一个指针(地址), 称为指针变量,使用指针变量等价于使用其内部存放的指针,所以我们有时也把指针变量简称为指针
&:只能操作左值(变量)
* :只能操作指针类型
&Num:
值:获得Num变量在内存空间中的首地址
类型:int * (&有类型升级的效果)
*Num:
值:获得&Num指针对应空间中的值
类型:int (*有类型降级效果)
注意:
1. 作为左值,将右值放入左边指针指向的空间
2. 作为右值,直接取指针指向空间中的值
举例:定义Num的值,输出 &Num 和 *&Num ,并对他赋值后在输出,查看效果:
#include
int main(void)
{
int Num = 0;
Num = 100;
printf("&Num = %p\n",&Num);
printf("*&Num = %d\n",*&Num);
*&Num = 200;
printf("*&Num = %d\n",*&Num);
Num = 300;
printf("*&Num = %d\n",*&Num);
return 0;
}
int *p;
int *q;
int *p, *q;
野指针:未经初始化的指针,指向已经被释放过空间的指针称为野指针,指针一定记得初始化
空指针:NULL 0x0,指向内存地址为0x0的指针
int *p = NULL;
注意:所有的指针变量占8个字节
直接访问:通过变量的变量名访问内存空间
间接访问:通过变量在内存中的地址访问变量空间
int *p = NULL;
int *q = NULL;
int a = 100;
int b = 200;
p = &a;
q = &b;
p = &b //将b的地址给指针变量p
*p = b //将b的值赋值给指针变量p所指向的值
p = q //将指针变量q所存放的地址给指针变量p
*p = *q //将指针变量q所指向的值赋值给指针变量p所指向的值
练习:从终端接收两个数,利用指针对这两个数完成四则运算打印结果
#include
int main(void)
{
int Num1 = 0;
int Num2 = 0;
int *p = NULL;
int *q = NULL;
p = &Num1;
q = &Num2;
scanf("%d%d", &Num1, &Num2);
printf("%d + %d = %d\n", *p, *q, *p + *q);
printf("%d - %d = %d\n", *p, *q, *p - *q);
printf("%d * %d = %d\n", *p, *q, *p * *q);
printf("%d / %d = %.2lf\n", *p, *q, *p / (*q+0.1));
return 0;
}
指针可以进行的算数运算:+、-、++、--
p++:向内存高地址偏移指向数据类型大小个字节空间
p--:向内存低地址偏移指向数据类型大小个字节空间
p - q
*p++; 等价于*p; p++;
(*p)++; 等价于:*p; *p++;
实参将值传递给形参,形参是实参的副本,形参改变不会影响实参
函数体内想使用函数体外部变量值的时候使用复制传递
实参地址传递给形参,形参就是实参的指针,可以通过对形参取*改变实参的值
函数体内想修改函数体外部变量值的时候使用地址传递
练习:封装一个函数获得数组中的最大值和最小值:
#include
int GetMaxMinNum(int array[], int len, int *Max, int *Min)
{
int i = 0;
*Max = array[0];
*Min = array[0];
for(i = 0; i < len; i++)
{
if(*Max < *(array+i))
{
*Max = *(array+i);
}
if(*Min > array[i])
{
*Min = array[i];
}
}
return 0;
}
int main(void)
{
int ary[5] = {0};
int len = sizeof(ary) / sizeof(ary[0]);
int i = 0;
int MaxNum = 0;
int MinNum = 0;
for(i = 0; i < len; i++)
{
scanf("%d",&ary[i]);
}
GetMaxMinNum(ary, len, &MaxNum, &MinNum);
printf("MaxNum = %d, MinNum = %d\n", MaxNum, MinNum);
return 0;
}
1. 封装一个函数,完成传入两个数值,获得这两个数值的最大公约数和最小公倍数
#include
int GetDivMulNum(int a, int b, int *Div, int *Mul)
{
int max = 0;
int min = 0;
int i = 0;
if(a > b)
{
max = a;
min = b;
}
else
{
max = b;
min = a;
}
for(i = max; i > 0; i++)
{
if(i % a == 0 && i % b ==0)
{
*Mul = i;
break;
}
}
for(i = min; i > 0; i--)
{
if(a % i == 0 && b % i == 0)
{
*Div = i;
break;
}
}
}
int main(void)
{
int Num1 = 0;
int Num2 = 0;
int divisor = 0;
int multiple = 0;
scanf("%d%d", &Num1, &Num2);
GetDivMulNum(Num1, Num2, &divisor, &multiple);
printf("最小公倍数 = %d, 最大公约数 = %d\n", multiple, divisor);
}
2. 求出数组a[N][N]中主对角线最大值和辅对角线最小值
注意:#define N 5
int a[N][N];
#include
#define N 5
int main(void)
{
int a[N][N] = {{12, 84, 91, 41, 51},
{54, 67, 16, 28, 34},
{84, 71, 46, 96, 33},
{63, 37, 73, 57, 11},
{77, 73, 39, 67, 98}};
int i = 0;
int max = 0;
int min = 0;
max = a[0][0];
min = a[0][0];
for(i = 0; i < N; i++)
{
if(max < a[i][i])
{
max = a[i][i];
}
if(min > a[i][i])
{
min = a[i][i];
}
}
printf("主对角线:max = %d, min = %d\n", max, min);
max = a[0][4];
min = a[0][4];
for(i = 0; i < N; i++)
{
if(max < a[i][N-1-i])
{
max = a[i][N-1-i];
}
if(min > a[i][N-1-i])
{
min = a[i][N-1-i];
}
}
printf("逆对角线:max = %d, min = %d\n", max, min);
}