在上一篇文章中,我们初步对C语言有了一定的认识。我们介绍了C语言中重要的一个结构main()函数,他是一个程序的入口。除此之外还了解了预处理头文件,对printf()函数也有了一定的初步认识。现在让我们一起继续深入学习。

今天要介绍的是C语言中的数据结构,包括int、char、float、double等等。除此之外还要深入介绍printf()函数以及sizeof()运算符。

引入

这天,开心每一秒在研究这个月的天气,但是天气数据都是用华氏度表示的,那怎么能让这些数据通过计算机,编写一个C语言程序,把他们都变成华氏度呢?华氏度转摄氏度的公式是:

$$ C=\left(F-32\right) \times 5 \div 9 $$

#include <stdio.h>

int main()
{
    // 定义整型int变量,并初始化为0
    int c = 0 ;
    int f = 0 ;
    // 输入华氏温度标
    printf("请输入华氏温标:") ;
    scanf("%d",&f) ;   //scanf函数,用于从控制台输入一个整数,并将其赋值给变量f
    // 计算摄氏温度标
    c = (f - 32) * 5 / 9 ;
    // 输出摄氏温度标
    printf("摄氏温标为: %d",c) ;
    return 0;
}

运行代码可以得到:

请输入华氏温标:114
摄氏温标为: 45

int类型

在C语言中,有许多整型变量,在不同的情况下,我们应该选择不同的数据类型。

int是一种有符号整型。一个int类变量必须是整数,它可以是正数、负数也可以是零。由于C/C++没有对字符占用进行规定,因此不同编译器的结果可能不同。在国际标准中规定C语言中int类型变量的取值范围最小值为-32768~32767。

1.声明一个int变量

在C语言中,声明一个变量只需要变量类型 变量名称

因此,如果我们要声明一个int类型的变量我们只需要int 变量名,例如int namesint ages等等。

但是,在C语言中并不是所有单词都可以被用作变量名以及函数名。这是因为在C语言中已经规定了部分关键字,这些关键字是不能用作函数名称,变量名称以及常量名称的。这些关键字是:

ISO C关键字
auto extern short while
break float signed _Alignas
case for sizeof _Atomic
char goto static _Bool
const if struct _Complex
continue inline switch _Generic
default int typedef _Imaginary
do long union _Noreturn
double register unsigned _Static_assert
else restrict void _Alignof
enum return volatile _Thread_local

除此之外,在日常书写代码过程中保持良好的代码命名规范是很有必要的。变量命名应该清晰工整,能够清晰反应变量用途,并且符合命名规范。这里介绍三种比较常见的命名方法以及一些使用场景。

  1. 驼峰命名法

    要求第一个单词首字母小写,后面其他单词首字母大写。

    int userName
    int userIdentity[10]
    float userConnectionCount
  2. 帕斯卡命名法

    要求每个单词的第一个字母都要大写。

    int UserName ;
    int UserIdentity[10] ;
    float UserConnectionCount ;
  3. 下划线命名法

    要求单词与单词之间用下划线隔开

    int user_name ;
    int user_identity[10] ;
    float user_connection_count ;
  4. 实际应用场景

    如今命名规则不断细化,很多时候十多种命名法组合使用。例如

    1. 全局变量通常使用g_+驼峰命名法如:

      int g_responseTimeout ;
    2. 常量全局变量通常使用全大写+下划线如:

      const int MAX_RETRY_TIMES = 2 ;

变量的初始化与赋值

在前面的代码中,我们对int c = 0 ;int f = 0 ;的操作就是对这两个变量进行初始化。

在C语言中,在完成对变量的声明后,只需要在变量名后加上=和要被赋值的值即可。例如:

int ages = 18 ;
int ages = 18 , nums = 10 ;
/*这种初始化方式在一些较老的编译器中并不支持,
虽然现代编译器大多数支持这种形式,但它并不是一种好的习惯
*/
int ages,nums = 10 ;

示例的最后一种初始化其实只对nums进行了初始化让其等于10,而ages事实上并没有被初始化。因此这种写法并不好,他很可能会让你误认为ages也被初始化了。

声明完变量后对其初始化是一件很有必要的事情。如果你只是声明了变量,那只是你在内存中申请了一块空间用于存放这一变量,由于运行过程中,这块内存空间被申请后可能还存在之前留下的脏数据,由此可能会导致没被初始化的变量在程序运行过程中出现错误。因此养成声明变量后就初始化的好习惯。

image-20260423132942-8sw938x.png

你也可以为变量赋值。在声明完变量后,你可以单独对变量进行赋值,例如:

int ages = 18 ;
ages = 22 ;

你也可以将运算结果赋值给变量如:

int ages = 18 ;
ages = age + 4 ; //结果也为22

这里ages原来存储的值18加上4得到了新的ages的值22。代码示例中的c = (f - 32) * 5 / 9 ;也是如此。

printf( )函数

在上一篇文章里,我们便已经接触过了printf()函数。我们通过这个函数输出了Hello World!这一串文字。而在这篇文章里,不难发现与之前不一样的是多了一个%d。那这个%d有什么用呢?%d称为转换说明,它指定了printf()函数应该用什么格式来显示一个值,我们后面会详细介绍它们。

基础用法

printf()函数最基础的用法就是在命令行中打出你想要输出的文字。例如我们之前用printf("Hello World!")打出了Hello World!的文字。

你只需要""中输入逆向输出的文字即可。

转换说明

正如我们上述所说,%d可以指定printf()函数应该用什么格式来显示一个值。我们只需要在引号后加上都好,并在逗号后填上你想输出的变量名,程序就会在输出时将%d变成你指定的那个变量名的量。

当然,逗号后不是只能填写变量名,它也可以是一个表达式,比如我们可以把我们上面的程序改成:

#include <stdio.h>

int main()
{
    int f = 0 ;
    printf("请输入华氏温标:") ;
    scanf("%d",&f) ;
    printf("摄氏温标为: %d",(f - 32) * 5 / 9) ;
    return 0;
}

这样我们便可以少定义一个变量。

如果你在一个printf()中想输出多个变量可以:

int a = 0 ;
int b = 1 ;
printf("a的值为:%d,b的值为:%d",a,b)

用逗号一次隔开变量名,程序在输出时就会按照你填写的顺序依次替换。

值得注意的是,转换说明的数量应该与待打印值的数量保持一致,不然可能会导致有变量无法被输出。

其他进制

除了十进制的数,在C语言中,你也可打印八进制和十六进制的数;只需要使用不同的转换说明即可。如果你要打印八进制数可以使用%o;如果你要打印十六进制数你可以使用%x。如果你想显示前缀0,0x,0X,那必须是用%#o%#x%#X

#include <stdio.h>

int main()
{
    int a = 10 ;
    printf("dec = %d , octal = %o , hex = %x \n",x,x,x) ;
    printf("dec = %d , octal = %#o , hex = %#x \n",x,x,x) ;
    return 0 ;
}

其他整数类型

除了int,C语言还规定了其他的整数类型用作不同的情况。C语言提供了三种附属关键词用于修饰基本的整数类型:short,long,unsigned

short int用在存储空间比int少的情况,通常用在存储数值比较少的情况。和int一样,short也是一个有符号类型。

long int用在存储空间比int多的情况,通常用在存储数值比较大的情况。long也是有符号类型。面对更大的整数存储场景,C语言还给出了long long类型的类型。

unsigned int只用于非负数的场景int允许的范围是是-32768~32767。而unsigned int的范围是0-65535,由于int中表示正负的第一位也被用来表示数,因此不带符号的unsigned类型可以表示比int更多的正整数。

那么如何定义这些变量嗯?与int一样,这些类型也是变量类型+变量名如:

long int usrID
long usrID

short int usrID
short usrID

unsigned int usrID
unsigned usrID

在下一篇番外:数据结构中会有详细介绍。当然再挖一个坑,后续还会单独开一个数据结构与算法的专栏。

再细一点

观察我们上面代码,我们输出的结果都是整数,那我们想输出更详细数值该怎么办呢?这时候浮点运算就该上场了。

#include <stdio.h>

int main()
{
    // 定义浮点型float变量,并初始化为0
    float c = 0.0 ;
    float f = 0 ;
    // 输入华氏温度标
    printf("请输入华氏温标:") ;
    scanf("%f",&f) ;   //scanf函数,用于从控制台输入一个浮点型数,并将其赋值给变量f
    // 计算摄氏温度标
    c = (f - 32) * 5 / 9 ;
    // 输出摄氏温度标
    printf("摄氏温标为: %f",c) ;
    return 0;
}
请输入华氏温标:114
摄氏温标为: 45.555557

浮点类型

浮点常量与变量

在C语言中,浮点类型有floatdoublelong double。在C语言中,浮点数与数学中的实数概念类似,他可以表示包括小数的更大范围的数字。浮点数的表示方法与科学计数法很像。例如,3.16E7代表$3.16 \times 10 ^ 7$(大写E小写e都可以)。总结下来浮点型常量的基本表达方式是:有符号的数字+e+有符号的数表示10的指数

需要注意的是:e(或E)之前必定有数字,e(或E)后不一定有数字,即可以没有小数部分如2E3,也可以没有指数部分如2.5,但不能二者都没有。浮点数中的正号可以省略,可以省略小数部分如2.e5,也可以省略整数部分如.2e5,但不能两者同时省略。还有,e和数字之间不要加空格。一下给出部分正确的表达:

1.1451
.5
2E5
2.
-2.5e11

通常,系统对于浮点常量会默认定义为double类型,例如:

float a ;
a = 2.5 * 1.1451

这里面2.5和1.1451都会被系统默认为double类型,算出结果后再截断成float类型。如果你就想让这些浮点常数是float类型,只需要在数字后加上f或者F即可。例如1.1451f

在C99标准中你还可以用十六进制表示浮点数。只需要在十六进制数前加上0x0X,将pP分别代替eE,将2的幂代替10的幂即可。例如0xb.5p5

在C语言中,float必须包含6位有效数字,float的范围是$10^{-37}$~$10^{37}$,一般占用32位。double是双精度浮点类型,它必须包含10位有效数字,取值范围与float一样,一般占用64位。

浮点类型变量的声明与其他变量一样:

float a ;
double b = 1.1451 ;

打印浮点数

printf()函数中,十进制表示的浮点类型的转换说明位%f,指数表示的浮点类型的转换说明位%e,如果你使用十六进制表示的浮点数,则用%a。例如:

#include <stdio.h>

int main()
{
    float a = 1.1451 ;
    float b = 2.5e6 ;
    
    printf("%f的指数形式是%e", a , a) ;
    printf("%e的十六进制形式是%a", b , b) ;
    return 0 ;
}
1.145100的指数形式是1.145100e+00
2.500000e+06的十六进制形式是0x1.312d000000000p+21

类型大小

由于C语言并没有明确要求不同类型的大小,因此我们需要一个函数来确定在该系统下这个类型的大小,这时候就该请出我们的sizeof()函数了;

#include <stdio.h>

int main()
{
    printf("int的类型大小是%zd\n", sizeof(int)) ;
    printf("long的类型大小是%zd\n", sizeof(long)) ;
    return 0 ;
}

总结

通过上面华氏度与摄氏度转换的例子,我相信你已经学会了整型和浮点型变量的定义与赋值,以及如何用printf()函数将它们输出出来。让我们回顾一下:

  1. 变量的定义、初始化、赋值

    int a ; //整型变量的定义
    float b ; //浮点型变量的定义
    
    long  c = 0 ; //整型变量的初始化
    double d = 25.9 ; //浮点型变量的初始化
    
    d = 2.e-3 ; //浮点型变量的赋值
  2. printf()函数的使用

    printf("%d %f",a , d) ; //输出整型a的值和十进制浮点d的值
    printf("%e",d) ; //输出指数形式浮点d的值