一、参数陷阱
各位读者是否还记得printf()输出函数的用法,传递给函数的信息被称为参数,如printf(“Hello,World!”);语句中函数调用了一个参数即 Hello,World!。双引号中的字符序列如(“Hello,World!”)被称为字符串(String),一个字符串就是一个参数。
同样的,scanf()输入函数与此类似,这两个函数不同于一般函数,他们的参数个数是可变的。printf()和 scanf() 函数用第 1个参数表明后续有多少个参数,即第 1个字符串中的转换说明与后面的参数-一对应。例如,下面的语句有两个,%d转换说明,说明后面还有两个参数:
printf("%d cats ate %d cans of tuna\n", cats, cans);
可以看到后面的确有cats,cans两个参数
C语言通过函数原型机制检查函数调用时的参数个数和类型是否正确,但是这对scanf和printf函数不起作用,因为这两个函数的参数个数是可变的,这就导致程序可以运行,但是参数匹配错误,结果差强人意
看下面一个例子
#include <stdio.h>
int main(void)
{
int n = 4;
int m = 5;
float f = 7.23;
float g = 9。83;
printf("%d\n", n, m); /*注释 参数太多 */
printf("%d %d %d\n", n); //注释参数太少
printf("%d %d\n", f, g); /* 值的类型不匹配 */
return 0;
}
运行结果如下
如图所示错误结果就是因为参数陷阱导致的问题,计算机在运行程序时可能不会捕获这类错误,只能靠程序员自己发现
注意:用%d来显示float类型的值,其值不会被转换成 int类型。在不同的平台下,缺少参数或参数类型不匹配导致的结果不同。
二、宏定义
宏定义时一般会定义符号常量,C语言中大部分语句后都要加分号,但是宏定义我在Dev-C++中实测,不能有分号,否则会报错,因为这是一种预处理器的替换机制使然,如下:
//计算圆的面积 ,使用宏定义符号常量
#include <stdio.h>
#define PI 3.14 // 定义圆周率常量
int main(void)
{
int r; // 圆的半径
float s; // 圆的面积
scanf("%d", &r); // 输入圆的半径
s = PI * r * r; // 计算圆的面积
printf("圆的面积为%f\n", s); // 输出圆的面积
return 0; // 函数返回
}
注意: 1. 一定一定一定不能在宏定义后加分号
2. 宏定义所用到的符号常量最好用大写易于区分
三、只读变量关键词
const简介
功能
- 修饰局部变量。使用const修饰的局部变量在初始化后其值就不能被修改。
- 修饰全局变量。与修饰局部变量类似,const修饰的全局变量也不能被直接或通过指针间接修改。
- 修饰指针变量。当const位于星号(*)的左边时,表示指针指向的内容是不可修改的;当const位于星号的右边时,表示指针本身是不可变的,即指针的地址不能被改变;当const位于星号的两边时,表示指针指向的内容和指针本身都是不可变的。
- 修饰函数参数。在函数参数前加上const可以确保参数在函数内部不会被修改,这有助于提高程序的安全性和可靠性。
- 修饰函数返回值。使用const修饰函数的返回值可以确保返回的值在使用过程中不会被修改。
注意:”只读变量“与”常量“不一样
下面给几个例子
- const在前面
const int nValue; //int是const
const char pContent; //char是const, pContent可变
const char const pContent;
- const在后面
int const nValue; //nValue是const
char const * pContent; //pContent是const, pContent可变
char const pContent; //pContent是const,pContent可变
char const const pContent; //pContent和*pContent都是const
补充信息
1.在c中,对于const定义的指针,不赋初值编译不报错,但在C++中不赋初值会报错。
2.强烈建议在初始化时说明指针的指向,防止出现野指针!
3.const不能赋值为原来的值,例如,const int nValue=4,nValue=4是错误的