此文章是我初学C语言时一些容易出错的地方,所以记录了下来。
对于初学C语言的同学应该会有帮助。
文章目录
1.scanf输入字符时吸收回车
我们先从下面这道题开始说起
ASCII码排序
输入三个字符后,按各字符的ASCII码从小到大的顺序输出这三个字符。
Input
输入数据有多组,每组占一行,有三个字符组成,之间无空格。
Output
对于每组输入数据,输出一行,字符中间用一个空格分开。
Sample Input
qwe
asd
zxc
Sample Output
e q w
a d s
c x z
代码
#include <cstdio>
#include <algorithm>
using namespace std;
int main(void)
{
char a[3];
while (scanf("%c%c%c", &a[0], &a[1], &a[2]) != EOF) {
getchar();
sort(a, a + 3);
printf("%c %c %c\n", a[0], a[1], a[2]);
}
return 0;
}
做这道题时,容易忽略掉第9行的getchar(),这时就会发现输出的情况有些奇怪。
对于scanf()和getchar()的解释
-
C语言中在读取键盘数据时,一般是带缓存的数据输入,需要按回车键才能完成该“行”数据的输入确认。①scanf()在读数值型数据或字符串时,会自动忽略前面的空白字符(空白字符指:回车,空格,TAB键),即从第一个非空白字符开始读取,而再次遇到空白字符结束该类型数据的输入。②scanf()在读取字符型数据时,空白字符也会被读取。
-
第8行代码中,有三个读取字符的scanf()函数,第一行输入"eqw"末尾的回车符会留在输入缓存区中。因此,在下一个读“字符”操作函数(getchar(), scanf("%c"), gets()等)运行时,会读到这个回车符。
-
因此,是否一定要在scanf()后面跟一个getchar()吸收回车,要看下一个输入的数据类型是什么,如果是读字符类操作,处理办法有多种方式。
-
对于scanf()函数,很值得我们深入的去了解一下。
2.字符串末尾的’\0’
我们也是从下面的题目开始引入
二进制转换
Input
输入一个整数n,(-2^31 < n < 2^31)
Output
将n转化为对应的二进制数,输出转化后的二进制长度和二进制数序列
Sample Input
5
Sample Output
101
代码
基本思路是利用短除法,每次求对2的余数,存入数组,最后逆序输出即为二进制数
一开始的错误代码
#include <stdio.h>
#include <string.h>
int main(void)
{
int n, len, i = 0;
char a[50];
scanf("%d", &n);
while(n != 0){
a[i++] = n % 2 + '0';
n /= 2;
}
len = strlen(a);
printf("二进制数长度:%d\n", len);
printf("二进制数:");
for (i = len - 1; i >= 0; i--)
printf("%c", a[i]);
puts("");
return 0;
}
输入5时的输出:
对strlen()和printf("%s", )的一些解释
- 运行上面的代码,会发现输出的len大于实际的长度,并且输出的二进制数也有乱码。
- 因为gets()或scanf(“%s", str) 都会在输入结束后自动在str的末尾添加 ‘\0’,而如果像上面这样单个字符赋值的话str末尾没有’\0’。
- 函数strlen()的参数必须是一个字符串,strlen是根据’\0’来判断字符串的结束的,所以当末尾不是0时,会读取str之外的内存,进而使得len的值大于实际字符串的值,从而输出乱码。
- 用printf("%s\n", str);输出str时同理,会一个字符一个字符地读取,直到读取到‘\0’才会结束,但是此时str结尾并没有‘\0’,则会读取str之外的内存,进而输出乱码。
- 解决方法:①直接将数组开在main函数之外,数组会全部初始化为0 ②因为’\0‘的ASCII码是0,所以我们可以将第7行改为 char a[50]={0}; 这样会把每个元素都初始化为0。
解决方法①
#include <stdio.h>
#include <string.h>
char a[50];
int main(void)
{
int n, len, i = 0;
scanf("%d", &n);
while(n != 0){
a[i++] = n % 2 + '0';
n /= 2;
}
len = strlen(a);
printf("二进制数长度:%d\n", len);
printf("二进制数:");
for (i = len - 1; i >= 0; i--)
printf("%c", a[i]);
puts("");
return 0;
}
解决方法②
#include <stdio.h>
#include <string.h>
int main(void)
{
int n, len, i = 0;
char a[50] = {
0};
scanf("%d", &n);
while(n != 0){
a[i++] = n % 2 + '0';
n /= 2;
}
len = strlen(a);
printf("二进制数长度:%d\n", len);
printf("二进制数:");
for (i = len - 1; i >= 0; i--)
printf("%c", a[i]);
puts("");
return 0;
}
后来改进的写法,直接用len作为下标来记录数组的长度
#include <stdio.h>
#include <string.h>
int main(void)
{
int n, len = 0, i;
char a[50];
scanf("%d", &n);
while(n != 0){
a[len++] = n % 2 + '0';
n /= 2;
}
printf("二进制数长度:%d\n", len);
printf("二进制数:");
for (i = len - 1; i >= 0; i--)
printf("%c", a[i]);
puts("");
return 0;
}
3.C语言对数组的初始赋值还有以下几点规定
- 可以只给部分元素赋初值。当{ }中值的个数少于元素个数时,只给前面部分元素赋值。例如:int a[10]={0,1,2,3,4};表示只给a[0]~a[4]5个元素赋值,而后5个元素自动赋0值。
- 只能给元素逐个赋值,不能给数组整体赋值。 例如给十个元素全部赋1值,只能写为:int a
[10]={1,1,1,1,1,1,1,1,1,1};而不能写为:int a[10]=1; - 如给全部元素赋值,则在数组说明中, 可以不给出数组元素的个数。例如:int a[5]=
{1,2,3,4,5};可写为:int a[]={1,2,3,4,5}; 动态赋值可以在程序执行过程中,对数组作动态赋
值。 这时可用循环语句配合scanf函数逐个对数组元素赋值。
4.对于没有初始化的数组
- 对于局部性质的数组:
① int a[100]; 这种写法因为没有初始化,所以100个元素都是机器垃圾值;
② int a[100] = {0, 2, 3}; 这种写法前3个元素被分别初始化为0、2、3,其余的都置为0;
③ int a[100] = {0}; 这种写法将100个元素都初始化为0。 - 对于全局或修饰为静态性质的数组:
若初始化则与以上②、③相同;若不初始化则全部元素自动置0。
5.对于没有初始化的变量
-
只有全局变量和静态变量才会自动初始化为0。
-
普通局部变量,若没初始化,则是随机数据。