C语言关于给变量、数组赋值的一些问题

此文章是我初学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()的解释

  1. C语言中在读取键盘数据时,一般是带缓存的数据输入,需要按回车键才能完成该“行”数据的输入确认。①scanf()在读数值型数据或字符串时,会自动忽略前面的空白字符(空白字符指:回车,空格,TAB键),即从第一个非空白字符开始读取,而再次遇到空白字符结束该类型数据的输入。②scanf()在读取字符型数据时,空白字符也会被读取。

  2. 第8行代码中,有三个读取字符的scanf()函数,第一行输入"eqw"末尾的回车符会留在输入缓存区中。因此,在下一个读“字符”操作函数(getchar(), scanf("%c"), gets()等)运行时,会读到这个回车符。

  3. 因此,是否一定要在scanf()后面跟一个getchar()吸收回车,要看下一个输入的数据类型是什么,如果是读字符类操作,处理办法有多种方式。

  4. 对于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", )的一些解释

  1. 运行上面的代码,会发现输出的len大于实际的长度,并且输出的二进制数也有乱码。
  2. 因为gets()或scanf(“%s", str) 都会在输入结束后自动在str的末尾添加 ‘\0’,而如果像上面这样单个字符赋值的话str末尾没有’\0’。
  3. 函数strlen()的参数必须是一个字符串,strlen是根据’\0’来判断字符串的结束的,所以当末尾不是0时,会读取str之外的内存,进而使得len的值大于实际字符串的值,从而输出乱码。
  4. 用printf("%s\n", str);输出str时同理,会一个字符一个字符地读取,直到读取到‘\0’才会结束,但是此时str结尾并没有‘\0’,则会读取str之外的内存,进而输出乱码。
  5. 解决方法:①直接将数组开在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语言对数组的初始赋值还有以下几点规定

  1. 可以只给部分元素赋初值。当{ }中值的个数少于元素个数时,只给前面部分元素赋值。例如:int a[10]={0,1,2,3,4};表示只给a[0]~a[4]5个元素赋值,而后5个元素自动赋0值。
  2. 只能给元素逐个赋值,不能给数组整体赋值。 例如给十个元素全部赋1值,只能写为:int a
    [10]={1,1,1,1,1,1,1,1,1,1};而不能写为:int a[10]=1;
  3. 如给全部元素赋值,则在数组说明中, 可以不给出数组元素的个数。例如:int a[5]=
    {1,2,3,4,5};可写为:int a[]={1,2,3,4,5}; 动态赋值可以在程序执行过程中,对数组作动态赋
    值。 这时可用循环语句配合scanf函数逐个对数组元素赋值。

4.对于没有初始化的数组

  1. 对于局部性质的数组:
    ① int a[100]; 这种写法因为没有初始化,所以100个元素都是机器垃圾值;
    ② int a[100] = {0, 2, 3}; 这种写法前3个元素被分别初始化为0、2、3,其余的都置为0;
    ③ int a[100] = {0}; 这种写法将100个元素都初始化为0。
  2. 对于全局或修饰为静态性质的数组:
    若初始化则与以上②、③相同;若不初始化则全部元素自动置0。

5.对于没有初始化的变量

  1. 只有全局变量和静态变量才会自动初始化为0。

  2. 普通局部变量,若没初始化,则是随机数据。

  • 10
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值