养成好的命名习惯
(1)函数名用大写字母开头的单词来命名。例如:
void InitPort(void);
void UpDisplay(void);
(2)变量用小写字母开头的单词来表示。例如:
uchar openLight;
uchar closeLight;
(3)常量用全大写的字母,并用下画线分隔单词。例如:
#define MAX_TIME 10
#define MIN_TIME 100
运算符的优先级
getchar 函数
函数 getchar 的功能是在键盘上输入一个字符并读取字符的值,其具体使用格式如下所示。
getchar();
在日常应用中,通常把输入的字符赋值给一个字符变量,构成赋值语句,例如下面的代码。
char char1;
char1=getchar(); //输入字符并把输入的字符赋值给一个字符变量
putchar(char1); //输出字符
在具体使用函数 getchar 时,应该注意如下 4 点。
(1)getchar 函数只能接受单个字符,输入的数字也按字符来处理。当输入多个字符时,只接收第 1 个字符。
(2)使用 getchar 函数前程序中必须包含文件“stdio.h”。
(3)在 Tuber C 屏幕下运行含本函数的程序时,将退出 Tuber C 屏幕进入用户屏幕等待用户输入。输入完毕再返回 Tuber C 屏幕。
(4)程序的最后两行可以用下面的任意一行来代替。
putchar(getchar());
printf("%c",getchar());
函数 getchar 有一个整型返回值。当程序调用 getchar 后,程序会一直等候用户按键输入。用户输入的字符存储在键盘缓冲区中,直到用户按 Enter 键为止(回车字符也放在缓冲区中)。当用户按 Enter 键之后,getchar 才开始从 stdin 流中读入字符,每次一个。getchar 函数的返回值是用户输入的第 1 个字符的 ASCII 码,如出错则返回 −1,且将用户输入的字符回显到屏幕上。如用户在按 Enter 键之前输入了多字符,则其他字符会保留在键盘缓存区中,等待后续 getchar 函数调用读取。也就是说,后续的 getchar 调用不会等待用户按键,而直接读取缓冲区中的字符,直到缓冲区中的字符读完为后才等待用户按键。
printf语句
函数 printf 又称为格式输出函数,关键字中的最后一个字母“f”有“格式”(format)之意。printf 函数的功能是按用户指定的格式,把指定的数据显示到显示器上。在前面的实例中,已多次使用过这个函数。
printf 函数的一般形式
函数 printf 是一个标准库函数,它的函数原型包含在头文件“stdio.h”中。但作为一个特例,不要求在使用 printf 函数之前必须包含 stdio.h 文 c 件。函数 printf 的一般格式如下。
printf("格式控制字符串",输出表列)
(1)“格式控制字符串”用于指定输出格式。格式控制字符串分为格式字符串和非格式字符串两种。格式字符串是以%开头的字符串,在%后面跟随各种格式的字符,目的是说明输出数据的类型、形式、长度、小数位数等。例如下面的格式。
- “%d”表示按十进制整型输出。
- “%ld”表示按十进制长整型输出。
- “%c”表示按字符型输出。
非格式字符串在输出时按原样输出,在显示中起到提示作用。
(2)“输出表列”给出了各个输出项,要求格式字符串和各输出项在数量和类型上一一对应。
scanf函数
函数 scanf 又称为格式输入函数,能够按用户指定的格式从键盘上把数据输入到指定的变量之中。
函数 scanf 的一般形式
函数 scanf 是一个标准的库函数,其函数原型包含在头文件“stdio.h”中。和函数 printf 相同,C 语言也允许在使用函数 scanf 之前不必包含 stdio.h 文件。使用函数 scanf 的一般格式如下所示。
scanf("格式控制字符串",地址列表);
其中,“格式控制字符串”的作用与函数 printfc 的相同,但是不能显示非格式字符串,即不能显示提示的字符串。地址列表给出各变量的地址。地址是由地址运算符“&”后跟变量名组成的。例如下面的代码分别表示变量a
和变量b
的地址。
&a, &b
上述地址就是编译系统在内存中给变量ac
、b
分配的地址。在 C 语言中,地址的概念与其他语言是不同的,应该把变量值和变量地址这两个不同的概念区别开来。变量地址是由 C 编译系统分配的,用户不必关心具体的地址是多少。
例如在赋值表达式a=123
中给变量赋值,则a
为变量名,123
是变量值,&a
是变量a的地址。
在赋值符号左边是变量名,不能写地址。而函数 scanf 在本质上也是给变量赋值,但它要求写变量的地址,例如&a
,这二者在形式上是不同的。单独一个&
是一个取地址运算符,而&a
是一个表达式,其功能是求变量的地址。
看下面的一段代码。
int main(void){
int a,b,c;
printf("input a,b,c\n");
scanf("%d%d%d",&a,&b,&c);
printf("a=%d,b=%d,c=%d",a,b,c);
}
在上述代码中,因为函数 scanf 本身不能显示提示字符,所以先用 printf 语句在屏幕上输出提示用户输入a
、b
、c
的值。当执行 scanf 语句后,程序会退出 Turbo C 屏幕进入用户屏幕以等待用户输入。用户输入 7 8 9 后按下 Enter 键,此时系统又将返回 Turbo C 屏幕。在 scanf 函数的格式串中,因为没有非格式字符在“%d%d%d”之间作输入时的间隔,所以在输入时要用多个空格或 Enter 键作为两个输入数之间的间隔。
格式字符串
函数 scanf 的格式字符串和函数 printf 的类似,以%开头,以一个格式字符结束,中间可以插入附加的字符。函数 scanf 的格式如下所示。
%[*][输入数据宽度][长度]格式字符
其中,方括号“[]”中的部分为可选项。在上述格式中各选项的具体说明如下所示。
- 格式字符。
格式字符用于标识输出数据的类型,各格式字符的具体说明如下表所示。
格式 | 字符意义 |
---|---|
d | 输入十进制整数 |
o | 输入八进制整数 |
x | 输入十六进制整数 |
u | 输入无符号十进制整数 |
f 或 e | 输入实型数(为小数形式或指数形式) |
c | 输入单个字符 |
s | 输入字符串 |
- “*”字符。
用以表示该输入项,读入后不赋值给相应的变量,即跳过该输入值。例如:
scanf("%d %*d %d",&a,&b);
当输入 1、2、3 时,会把 1 赋值给a
,跳过 2,3 赋值给b
。
- 宽度。
用十进制整数指定输入的宽度(即字符数)。例如:
scanf("%5d",&a);
如果输入“12345678”,则会把 12345 赋值给变量a
,截去其余部分。例如:
scanf("%4d%4d",&a,&b);
如果输入“12345678”,则会把 1234 赋值给a
,而把 5678 赋值给b
。
- 长度。
长度格式符是 l 和 h,l 表示输入长整型数据(如%ld)和双精度浮点数(如%lf);而 h 则表示输入短整型数据。
在 C 语言中使用函数 scanf 时,必须注意以下 6 点。
(1)在函数 scanf 中没有精度控制,例如scanf("%5.2f",&a)
;是非法的。不能用此语句输入小数位数为两位的实数。
(2)scanf 中要求给出变量地址,如给出变量名则会出错。例如scanf("%d",a)
;是非法的,应改为scanf("%d",&a)
;这才是合法的。
(3)在输入多个数据时,若格式控制字符串中没有使用非格式字符作为输入数据之间的间隔,则可用空格、制表符或回车符。在编译时如果遇到空格、Tab、Enter 或非法数据(如对“%d”输入“12A”时,A 即为非法数据),则认为该数据输入结束。
(4)在输入字符数据时,若格式控制字符串中无非格式字符,则认为所有输入的字符均为有效字符。例如:
scanf("%c%c%c",&a,&b,&c);
如果输入d``e``f
,则会把d
赋值给a
,把空格赋值给b
,把e
赋值给c
。只有当输入为def
时,才能把d
赋值给a
,把e
赋值给b
,把f
赋值给c
。如果在格式控制中加入空格作为间隔,例如,
scanf ("%c %c %c",&a,&b,&c);
则输入时可在各数据之间加空格。
看下面的一段代码。
int main(void){
char a,b;
printf("input character a,b\n");
scanf("%c%c",&a,&b);
printf("%c%c\n",a,b);
}
在上述代码中,因为在 scanf 函数"%c%c"中没有空格,所以输入“M N”后,输出结果中只有 M。而输入改为 MN 时才可以输出 MN 两个字符。
(5)如果格式控制字符串中有非格式字符,则输入时也要输入该非格式字符。例如:
scanf("%d,%d,%d",&a,&b,&c);
其中,用非格式符“,”作为间隔符时,应为 5、6、7。例如:
scanf("a=%d,b=%d,c=%d",&a,&b,&c);
此时输入应该为a=5
,b=6
,c=7
。
(6)如果输入的数据与输出的类型不一致时,虽然编译能够通过,但结果将不正确。
puts 函数
函数 puts 的头文件是 stdio.h,其功能是向标准输出设备写字符串并自动换行,直至接收到换行符或 EOF 时停止,并将读取的结果存放在由 str 指针所指向的字符数组中。换行符不作为字符串的内容,读取的换行符转换为空值,并由此来结束字符串。
使用函数 puts 的语法格式如下所示。
puts(字符串参数)
其中,“字符串参数”可以是字符串数组名或字符串指针,也可以是字面字符串,并且该字符串参数可以包含转义字符,但是不能包含格式字符串。具体说明如下所示。
- 函数 puts 只能输出字符串,而不能输出数值或进行格式变换。
- 可以将字符串直接写入到函数 puts 中。
- 由于函数 puts 可以无限读取,却不会判断上限,所以程序员应该确保 str 的空间足够大,以便在执行读操作时不会发生溢出。
C11 标准函数 gets_s
函数 gets_s 的功能是,从标准输入设备(stdin)上读取 1 个字符串(可以包含空格),并将其存储到字符数组中去,并用空字符(\0)代替输入字符串中的换行符。在 C11 标准之前,此函数名为 gets。函数 gets_s 读取的字符串的长度没有限制,程序员要保证字符数组有足够大的空间,以存放输入的字符串。如果调用成功则返回字符串参数 s;如果遇到文件结束或出错,则返回空值。该函数输入的字符串中允许有空格,而函数 scanf()则不允许。
使用函数 gets 的语法格式如下所示。
gets(字符数组)
gets_s 函数和 scanf 函数的区别
scanf 函数和 gets_s 函数都可用于输入字符串,但在功能上有所区别。若想从键盘上输入字符串“hi hello”,则应该使用 gets_s 函数。gets_s 可以接收空格,而 scanf 遇到空格、回车符和制表符都会认为输入结束,所以它不能接受空格。例如:
char string[15]; gets_s (string); /*遇到回车符为认为输入结束*/
scanf("%s",string); /*遇到空格会认为输入结束*/
在输入字符串中包含空格时,应该使用 gets 输入。
在 C 语言中,至少有两个能够获取字符串的函数:scanf 和 gets_s。二者的不同点如下所示。
- scanf 不能接受空格、制表符、回车符等。
- gets_s 能够接受空格、制表符和回车符等。
二者的相同点如下所示:
- 在字符串结束后会自动加'\0'。
- 当 scanf 函数遇到回车符、空格和制表符后会自动在字符串后面添加'\0',但是回车符、空格和制表符仍会留在输入的缓冲区中。
- gets_s 可以接受 Enter 键之前输入的所有字符,并用'\n'替代 '\0',回车符不会留在输入缓冲区中。
- 用 gets_s 读取字符串,用 Enter 结束输入。
- scanf 可以读取所有类型的变量。
克服 gets_s 函数的缺陷
在 C 语言中函数 gets_s 是从 stdin 流中读取字符串的函数,此函数接受从键盘上输入的字符直到遇到 Enter 键时终止。函数 gets_s 的原型是:
char* gets(char *buff);
例如:
#include <stdio.h>
int main(void)
{
charstr[30];
while(!str!= gets_s (str));
printf("%s\n",str);
return 0;
}
如果读取成功,gets_s 函数的返回值是和 str 值相同的指针,否则返回空指针。
函数 gets_s 是一个危险的函数,原因是用户在键盘上输入的字符个数可能大于缓冲区的最大值,而函数 gets_s 并不对其检查。当用户在键盘上输入多个数据时,程序有可能会发生崩溃。解决方法是重写一个新的函数 gets_s,原型是:
char* Gets(int maxlen)
这个函数可让程序员指定输入字符的最大个数,在函数中为字符分配存储空间,函数返回 char*。
这个函数是针对动态数组而编写的,例如:
int main(void)
{
char*p;
p=Gets(18);
}
函数 gets_s 中的参数舍弃传入指针的原因是传入函数的指针可能不可靠,这样会造成程序崩溃,比如传入一个野指针。
另一个 gets_s 函数的原型是:
char* const Gets(char* const array,int maxlen);
这个函数针对固定长度的字符数组进行输入,例如:
int main(void)
{
charstr[20];
Gets(str,20);
return 0;
}
此时函数 gets_s 中的有一个参数是 char* const 类型,原因是它允许程序员修改这个类型指针所指向的内容,但不能修改指针本身。具体实现代码如下。
#include <string.h>
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <io.h>
char* Gets(int maxlen)
//最多从键盘上读入maxlen个字符,返回字符串指针类型
{
int i;
staticchar* str;
char c;
str=(char*)malloc(sizeof(char) *maxlen);
if(!str)
{
perror("memeoryallocation error!\n");
return0;
}
else
{
for(i=0;i<maxlen;i++)
{
c=getchar();
if(c!='\n')str[i]=c;
elsebreak;
}
str[i]='\0';
returnstr;
}
}
char* const Gets(char* const array,int maxlen)
{
int i;
char c;
for(i=0;i<maxlen;i++)
{
c=getchar();
if(c!='\n')array[i]=c;
elsebreak;
}
array[i]='\0';
returnarray;
}
int main(void)
{
char s[8];
Gets(s,8);
puts(s);
fflush(stdin); //刷新输入缓冲区,这很重要,否则会影响下一个Gets函数
char*p=Gets(8);
puts(p);
return 0;
}
C 语言的输入和输出问题
请看下面的代码。
#include<stdio.h>
int main(void)
{
putchar(getchar());
putchar(getchar());
putchar(getchar());
putchar('\n');
}
输入a
,按下 Enter 键,输入b
,按下 Enter 键后,运行就结束了。运行结果为:
a
a
b
b
这是因为当你输入a
并按下 Enter 键时,系统得到两个字符,一个是a
,另一个是 Enter 键。所以系统会输出a
和回车符,这是第 2 个a
的由来。第一个a
以及紧接着的 Enter 回车符都是用户输入的,它们作为 getchar 的返回值返回给 putchar。所以第 2 个a
和紧接着的 Enter 键就是 putchar 的两次返回值。b
的产生过程同理。其实,b
后面还有个 Enter 键,只是没在意而已。
造成上述问题的原因是没有清空缓冲区里数据,我们可以将程序修改为如下形式。
#include<stdio.h>
int main(void)
{
putchar(getchar());
fflush(stdin);
putchar(getchar());
fflush(stdin);
putchar(getchar());
putchar('\n');
}
这样当每次输入后,会强制清空标准输入流。