c语言----顺序结构
顺序结构的基本概念
- 定义:顺序结构是C语言程序中最基本的结构,它按照语句的先后顺序依次执行。就像我们日常做事一样,一步一步地按照顺序来完成任务。在C语言程序中,从程序的第一条语句开始,逐句向下执行,直到最后一条语句结束。
- 示例简单代码段理解顺序结构:
#include <stdio.h>
int main() {
int a = 5;
int b = 3;
int sum = a + b;
printf("两数之和为:%d\n", sum);
return 0;
}
- 在这个代码段中,首先定义了两个变量
a
和b
,并分别初始化为5
和3
。接着计算它们的和并存储在变量sum
中,最后通过printf
函数输出结果。语句的执行顺序是固定的,先完成变量定义和初始化,再进行求和运算,最后输出结果。
-
语句的顺序执行特点
- 变量赋值与使用顺序:在顺序结构中,变量必须先定义或赋值,才能在后续的语句中正确使用。例如:
#include <stdio.h> int main() { int result; result = 10 / 2; // 正确,因为除数和被除数是已知的常量 int dividend = 20; int divisor = 4; int new_result = dividend / divisor; // 正确,因为dividend和divisor已经赋值 printf("两个结果分别为:%d和%d\n", result, new_result); return 0; }
- 如果变量没有先进行赋值就使用,可能会导致未定义行为。例如,下面的代码是错误的:
#include <stdio.h> int main() { int num; int double_num = num * 2; // 错误,num未初始化 printf("结果:%d\n", double_num); return 0; }
- 函数调用顺序:在顺序结构中,函数调用也是按照顺序进行的。例如:
#include <stdio.h> void printMessage() { printf("这是一个消息\n"); } int calculateSum(int a, int b) { return a + b; } int main() { printMessage(); int sum = calculateSum(3, 5); printf("两数之和为:%d\n", sum); return 0; }
- 首先调用
printMessage
函数输出一条消息,然后调用calculateSum
函数计算两数之和并输出结果。函数调用的顺序会影响程序的输出和逻辑。
-
顺序结构在程序中的重要性和应用场景
- 简单计算和赋值任务:顺序结构常用于简单的数学计算、变量赋值等操作。比如在计算圆的面积和周长的程序中,先根据用户输入的半径计算面积和周长,然后输出结果,这整个过程可以用顺序结构实现。
#include <stdio.h> #define PI 3.14159 int main() { double radius; printf("请输入圆的半径:"); scanf("%lf", &radius); double area = PI * radius * radius; double circumference = 2 * PI * radius; printf("圆的面积为:%lf,周长为:%lf\n", area, circumference); return 0; }
- 初始化操作和数据准备:在复杂的程序开始阶段,顺序结构用于初始化各种数据结构、变量和资源。例如,在一个游戏程序中,可能需要先初始化游戏场景、角色属性等数据,这些操作可以按照顺序依次完成,为后续的游戏逻辑(如游戏循环中的更新和渲染)做好准备。
C语言中的输入和输出
以下是对C语言中常见输入输出函数更详细的讲解,并配有相应的代码示例:
1. printf()
函数
-
功能:
printf()
函数用于将格式化的数据输出到标准输出设备(通常是显示器)。它可以按照指定的格式控制符来输出不同类型的数据,并且能灵活组合文本与变量值进行输出。 -
语法格式:
printf("格式控制字符串", 输出列表);
其中,“格式控制字符串”包含普通字符(原样输出的文本内容)和格式控制符(用于指定对应变量的输出格式),“输出列表”则是要输出的变量或表达式,变量的数量和类型要与格式控制符一一对应。
- 常用格式控制符及示例代码:
%d
(十进制整数输出):
#include <stdio.h>
int main() {
int num = 10;
printf("The number is %d\n", num);
return 0;
}
在上述代码中,定义了一个整型变量num
并赋值为10
,printf()
函数中的%d
格式控制符会将num
的值以十进制整数形式输出,运行结果会显示The number is 10
。
- **`%f`(单精度浮点数输出)**:
#include <stdio.h>
int main() {
float f = 3.14f; // 注意单精度浮点数后面要加f后缀
printf("The float number is %f\n", f);
return 0;
}
这里定义了单精度浮点数f
并赋值为3.14
,通过%f
格式控制符将其输出,运行后会显示The float number is 3.140000
(默认会输出小数点后6位)。
- **`%lf`(双精度浮点数输出)**:
#include <stdio.h>
int main() {
double d = 3.1415926;
printf("The double number is %lf\n", d);
return 0;
}
定义双精度浮点数d
后,使用%lf
格式控制符输出它,结果会按双精度的格式显示相应的值,比如The double number is 3.141593
(同样默认小数点后6位,具体精度可能因编译器等因素略有不同)。
- **`%c`(字符输出)**:
#include <stdio.h>
int main() {
char ch = 'A';
printf("The character is %c\n", ch);
return 0;
}
代码中定义字符变量ch
并赋值为'A'
,%c
格式控制符就将该字符输出,显示为The character is A
。
- **`%s`(字符串输出)**:
#include <stdio.h>
int main() {
char str[] = "C Language";
printf("The string is %s\n", str);
return 0;
}
定义字符数组str
存储字符串,%s
格式控制符会将整个字符串输出,输出结果为The string is C Language
。
2. scanf()
函数
-
功能:
scanf()
函数用于从标准输入设备(通常是键盘)读取用户输入的数据,并按照指定的格式将数据存储到相应的变量中。 -
语法格式:
scanf("格式控制字符串", 地址列表);
“格式控制字符串”规定了输入数据的格式类型,“地址列表”则是要存储输入数据的变量的地址(通过取地址运算符&
获取),且格式控制符的类型和数量必须与地址列表中变量的类型和数量严格匹配。
- 示例代码及注意事项:
- 读取单个整数:
#include <stdio.h>
int main() {
int num;
printf("Please enter an integer: ");
scanf("%d", &num);
printf("You entered: %d\n", num);
return 0;
}
在这个程序中,首先提示用户输入一个整数,然后通过scanf("%d", &num)
语句从键盘读取一个十进制整数并存储到num
变量中,最后再用printf()
函数输出用户输入的整数。运行时,用户输入一个整数(如5
)并回车,程序就会显示You entered: 5
。
- **读取多个整数**:
#include <stdio.h>
int main() {
int num1, num2;
printf("Please enter two integers separated by a space: ");
scanf("%d %d", &num1, &num2);
printf("You entered: num1 = %d, num2 = %d\n", num1, num2);
return 0;
}
这里要读取两个整数,在输入时需要用空格或者回车键来分隔两个数。例如用户输入3 4
(中间用空格分隔),程序会将3
存储到num1
,4
存储到num2
,并输出相应的提示信息显示这两个数的值。
- **字符串输入的注意事项(避免缓冲区溢出)**:
#include <stdio.h>
int main() {
char str[5];
printf("Please enter a string (limit to 4 characters): ");
scanf("%4s", str); // 使用%ns格式控制符限制长度
printf("You entered: %s\n", str);
return 0;
}
定义长度为5
的字符数组str
,使用%4s
格式控制符来限制输入字符串的长度,最多读取4
个字符(要留一个位置给字符串结束符\0
),避免了因输入过长字符串导致的缓冲区溢出问题。比如用户输入abcd
,程序会正常输出You entered: abcd
;若输入超过4
个字符,多余部分会被舍弃。
3. puts()
函数
-
功能:
puts()
函数用于输出一个字符串到标准输出设备,并自动在字符串末尾添加换行符,使输出的字符串独占一行,操作相对简洁,专门用于字符串的输出。 -
示例代码:
#include <stdio.h>
int main() {
char str[] = "This is a test string";
puts(str);
return 0;
}
定义了字符数组str
存储一个字符串,调用puts(str)
函数后,会在屏幕上输出This is a test string
并自动换行。
4. gets()
函数(不推荐使用)
-
功能:
gets()
函数用于从标准输入读取一个字符串,它会持续读取字符,直到遇到换行符\n
为止,然后将读取到的字符序列(包含换行符替换为字符串结束符\0
)存储到指定的字符数组中。 -
示例代码(虽然不推荐,但示例展示功能):
#include <stdio.h>
int main() {
char str[20];
printf("Please enter a string: ");
gets(str);
puts(str);
return 0;
}
在上述代码中,提示用户输入一个字符串,然后通过gets(str)
读取用户输入的字符串并存储到str
字符数组中,最后用puts(str)
输出该字符串。然而,由于gets()
函数不检查输入字符串的长度,很容易导致缓冲区溢出,比如定义的str
数组长度为20
,若用户输入超过19
个有效字符(加上字符串结束符\0
共20
个字符的空间限制),就会出现缓冲区溢出的安全隐患,所以现代编程中不推荐使用它。
5. fgets()
函数
-
功能:
fgets()
函数用于从指定的文件流(可以是标准输入stdin
,也可以是其他打开的文件流)读取一个字符串。它会按照指定的读取字符数上限来读取字符,并且如果在读取过程中遇到换行符\n
,也会一并读取进来,最后会在读取的字符串末尾添加字符串结束符\0
,有效避免了缓冲区溢出问题。 -
语法格式:
fgets(字符数组名, 读取字符数的上限, 文件流指针);
-
示例代码(针对标准输入情况):
#include <stdio.h>
int main() {
char str[20];
printf("Please enter a string: ");
fgets(str, 20, stdin);
printf("You entered: %s", str);
return 0;
}
这里定义长度为20
的字符数组str
,通过fgets(str, 20, stdin)
从标准输入读取字符串,最多读取19
个字符(要留一个位置给\0
),如果输入的字符串较短且包含换行符,换行符也会被读取进来并正常输出,避免了因输入过长字符串导致的缓冲区溢出情况,保证了程序的安全性。
6. putchar()
函数
-
功能:
putchar()
函数用于输出一个字符到标准输出设备,功能比较单一,就是简单地将一个字符显示出来,常用于只需要输出单个字符的场景,使用起来比printf("%c", ch)
更加简洁。 -
示例代码:
#include <stdio.h>
int main() {
char ch = 'a';
putchar(ch);
putchar('\n'); // 输出换行,让显示更清晰,也可使用printf("\n");
return 0;
}
定义字符变量ch
并赋值为'a'
,调用putchar(ch)
函数就会在屏幕上输出字符a
,后面再通过putchar('\n')
输出一个换行符,让显示效果更清晰,若不添加换行符,后续的命令提示符等可能紧接着输出的字符显示。
7. getchar()
函数
-
功能:
getchar()
函数用于从标准输入设备读取一个字符,程序执行到该函数时会暂停,等待用户输入一个字符,然后将其返回并可存储到相应的变量中,常用于获取用户简单的单个字符输入,比如菜单选择等交互操作。 -
示例代码:
#include <stdio.h>
int main() {
char ch;
printf("Please enter a character: ");
ch = getchar();
printf("You entered: %c\n", ch);
return 0;
}
程序先提示用户输入一个字符,然后通过getchar()
函数读取用户输入的字符并存储到ch
变量中,最后用printf()
函数输出用户输入的字符,比如用户输入b
,程序就会显示You entered: b
。
C语言输入输出的常见错误有哪些?
scanf()
函数相关错误- 格式控制符与变量类型不匹配
- 错误示例:
- 格式控制符与变量类型不匹配
#include <stdio.h>
int main() {
int num;
scanf("%f", &num);
printf("The number is %d\n", num);
return 0;
}
- **解释**:
- 这里`scanf()`函数使用`%f`格式控制符来读取数据,但是要存储数据的变量`num`是`int`类型。这会导致存储的数据不符合预期,因为`%f`会按照浮点数的格式读取数据,而`int`变量无法正确存储浮点数格式的数据。
- 正确的做法是将`scanf()`函数中的格式控制符改为`%d`,使其与变量类型相匹配。
- 忘记使用取地址运算符
&
- 错误示例:
#include <stdio.h>
int main() {
int num;
scanf("%d", num);
printf("The number is %d\n", num);
return 0;
}
- **解释**:
- `scanf()`函数需要变量的地址来存储读取到的数据。在这个例子中,没有使用`&`获取`num`的地址,会导致程序在运行时出现错误,可能会导致程序崩溃或者出现不可预测的行为。
- 一定要记住在`scanf()`函数中,对于普通变量(除了数组名本身代表地址外)都要使用`&`来获取地址。
- 缓冲区溢出(字符串输入)
- 错误示例:
#include <stdio.h>
int main() {
char str[5];
scanf("%s", str);
printf("The string is %s\n", str);
return 0;
}
- **解释**:
- 当用户输入的字符串长度超过`4`个字符(因为还要留一个位置给字符串结束符`\0`)时,就会发生缓冲区溢出。这可能会导致程序出现错误,甚至可能会覆盖其他内存区域的数据。
- 为了避免这个问题,可以使用`%ns`格式控制符(`n`为指定的长度)来限制读取字符串的长度,比如`scanf("%4s", str);`。
printf()
函数相关错误- 格式控制符与变量类型不匹配
- 错误示例:
- 格式控制符与变量类型不匹配
#include <stdio.h>
int main() {
float f = 3.14;
printf("The number is %d\n", f);
return 0;
}
- **解释**:
- 这里`printf()`函数使用`%d`格式控制符来输出浮点数`f`的值。由于`%d`用于输出整数,所以会导致输出结果不符合预期,可能会输出一些奇怪的值。
- 正确的做法是将格式控制符改为`%f`,即`printf("The number is %f\n", f);`。
- 输出列表中的变量数量与格式控制符数量不匹配
- 错误示例:
#include <stdio.h>
int main() {
int num1 = 1, num2 = 2;
printf("The numbers are %d\n", num1);
return 0;
}
- **解释**:
- 定义了两个变量`num1`和`num2`,但是`printf()`函数的格式控制字符串中只有一个`%d`,导致`num2`没有被输出。
- 可以修改为`printf("The numbers are %d and %d\n", num1, num2);`,使格式控制符的数量和变量的数量相匹配。
- 文件结束符相关错误(输入)
- 在使用
scanf()
等输入函数时,没有正确处理文件结束符(EOF
)的情况。例如,在循环读取输入数据时,如果没有正确检测EOF
,可能会导致程序陷入无限循环或者异常退出。 - 错误示例(循环读取整数):
- 在使用
#include <stdio.h>
int main() {
int num;
while (1) {
scanf("%d", &num);
printf("The number is %d\n", num);
}
return 0;
}
- 解释:
- 这个程序会不断地读取整数并输出,但是没有办法正常结束循环。当遇到文件结束符(例如在控制台输入
Ctrl + Z
(Windows)或者Ctrl + D
(Unix/Linux))时,程序应该有相应的机制来退出循环。 - 正确的做法可以是通过
scanf()
函数的返回值来判断是否读取到了数据。scanf()
函数在成功读取数据时会返回读取到的变量数量,当遇到EOF
时会返回EOF
(通常定义为-1
)。可以修改为:
- 这个程序会不断地读取整数并输出,但是没有办法正常结束循环。当遇到文件结束符(例如在控制台输入
#include <stdio.h>
int main() {
int num;
int result;
while ((result = scanf("%d", &num))!= EOF) {
printf("The number is %d\n", num);
}
return 0;
}
- 混合输入输出导致的错误(缓冲问题)
- 在混合使用
scanf()
和其他输入函数(如getchar()
)时,可能会出现缓冲问题。例如,scanf()
函数在读取数据后会在输入缓冲区留下换行符,当紧接着使用getchar()
读取字符时,可能会直接读取到这个换行符,而不是用户期望输入的字符。 - 错误示例:
- 在混合使用
#include <stdio.h>
int main() {
int num;
char ch;
scanf("%d", &num);
ch = getchar();
printf("The character is %c\n", ch);
return 0;
}
- 解释:
- 假设用户输入一个整数
1
然后回车,scanf()
函数会读取1
,但是回车键产生的换行符\n
会留在输入缓冲区。当getchar()
函数执行时,它会直接读取这个换行符,而不是用户期望输入的另一个字符。 - 解决这个问题的一种方法是在
scanf()
和getchar()
之间添加一个getchar()
函数来读取并丢弃这个换行符,例如:
- 假设用户输入一个整数
#include <stdio.h>
int main() {
int num;
char ch;
scanf("%d", &num);
getchar(); // 读取并丢弃换行符
ch = getchar();
printf("The character is %c\n", ch);
return 0;
}