乐趣区

关于c:数据与C

变量与常量

为了可能更加不便的应用数据,程序员会将在程序运行期间会扭转或赋值的数据应用变量进行保留。常量则是事后定义好,在程序运行期间不会扭转的固定值

变量和常量就如同是一个盒子,能够用来装货色(数据)。在计算机中,数据是寄存在内存中的,存放数据的内存空间程序员为了不便当前的应用,都会起一个好记的名字。这个名称也由字母、数字和下划线组成,必须要以字母和下划线结尾。因为 C 语言是对大小写敏感的,所以大写字母和小写字母是不同的,也就是变量名 abc 和 Abc 是两个不同的变量。

数据类型

不同的数据类型有不同的含意,有的数据类型示意整数,有的示意字符,有的示意浮点数。常量能够是任何的数据类型,通过常量的值辨认(100 是整数,123.45 是浮点数)。而变量则须要指定数据类型。在 C 语言中有很多种数据类型,从最后的 K &R 给出的 7 个数据类型关键字,再到 C90 增加的 2 个新的关键字,到最初的 C99 增加的 3 个关键字

最后 K &R 给出的关键字 C90 规范增加的关键字 C99 规范增加的关键字
int signed _Bool
long void _Complex
short _Imaginary
unsigned
char
float
double

int、long、short、unsigned 和 C90 新增加的 signed 关键字用于示意整数类型,unsigned 示意无符号数,signed 则示意有符号数,整数类型的例子:unsigned short int 和 long long int

char 关键字用于寄存字母和其余字符(如:$、% 等),char 也能够用来示意较小的整数

float、double 和 long double 示意浮点数

_Bool 示意布尔类型(true 或 false)

_Complex 和_Imaginary 别离示意复数和虚数

存储大小

不同的数据类型能够寄存的数据大小是不同的,可能寄存的数据越多,值越大。

数据类型 存储大小
char 1 字节
int 2 或 4 字节()
short 2 字节
long 4 字节
float 4 字节
double 8 字节
long double 16 字节

在 C 语言中,能够通过 sizeof 运算符查看数据类型存储字节的大小

#include<stdio.h>

int main()
{printf("char 的存储大小: %d\n", sizeof(char));
    printf("short 的存储大小: %d\n", sizeof(short));
    printf("int 的存储大小: %d\n", sizeof(int));
    printf("long 的存储大小: %d\n", sizeof(long));
    printf("float 的存储大小: %d\n", sizeof(float));
    printf("double 的存储大小: %d\n", sizeof(double));
    printf("long double 的存储大小: %d\n", sizeof(long double));

    return 0;
}

运行后果:

这里应用到的 printf()函数,前面会进行解说,目前只须要晓得 printf()是用来打印内容到屏幕上的就能够了。

变量的定义

C 语言提供了很多种数据类型,在定义变量时须要指定变量的数据类型,如整数能够应用 int 类型,小数能够应用 float 类型等,上面将开始介绍如何定义变量。

定义变量

定义变量的语法:数据类型 变量名;

举个例子,上面的程序用于计算两个整数的和

#include<stdio.h>

int main()
{
    int num1;   // 定义一个变量 num1,用于寄存第一个数
    int num2;   // 定义一个变量 num2,用于寄存第二个数
    int sum;    // 定义一个变量 sum,用于寄存两个数的和
    
    num1 = 100;        // 将整数 100 赋值给变量 num1
    num2 = 200;
    sum = num1 + num2;  // 计算 num1 与 num2 相加,并将值赋值给 sum 变量

    printf("num1 + num2 = %d\n", sum);      // 将 sum 的值打印到屏幕

    return 0;
}

运行后果:

在申明 num1 和 num2 变量时,并没有给它们提供初始值。num1 和 num2 是通过前面的 num1 = 100;num2 = 200; 获取到值的,这种行为称为初始化。初始化就是给变量一个初始值。

定义变量时初始化

在下面的例子中,定义变量与给初始化变量是分成两步的,也能够将这两步合并在一起,将程序修改后如下:

#include<stdio.h>

int main()
{
    int num1 = 100;   // 定义变量 num1 并将 100 赋值给 num1
    int num2 = 200;
    int sum = num1 + num2;   //num1 与 num2 相加后的后果赋值给 sum 变量

    printf("num1 + num2 = %d\n", sum);      // 将 sum 的值打印到屏幕

    return 0;
}

间断定义多个变量

批改后的程序比之前的简洁了,接着咱们发现 num1 和 num2 的数据类型是雷同的,都是 int 类型,那么这两个变量就能够一起定义,还是下面的例子,批改后如下:

#include<stdio.h>

int main()
{
    int num1 = 100, num2 = 200;     // 同时申明 num1 和 num2 并赋值
    int sum = num1 + num2;   //num1 与 num2 相加后的后果赋值给 sum 变量

    printf("num1 + num2 = %d\n", sum);      // 将 sum 的值打印到屏幕

    return 0;
}

须要留神的是,为了不让人误会在同时定义多个变量时,有的变量不须要初始化,而有的变量须要进行初始化。那么不倡议写在一起,倡议离开定义,如int num1, num2= 200; 这样写很容易让人误以为 num1 和 num2 的值都是 200,所以不倡议这么写,当然这么写是不会报错的。

常量的定义

通过一个例子开始解说常量的应用,上面的程序的作用是计算圆的周长和面积:

#include<stdio.h>

int main(void)
{
    float pi = 3.14159;     // 圆周率
    int r = 5;              // 圆的半径

    float area = pi * r * r;        // 计算圆的面积
    float circum = 2 * pi * r;      // 计算圆的周长

    printf("半径为 %d 的圆面积是: %.2f, 周长是: %.2f", r, area, circum);

    return 0;
}

通过下面的例子能够晓得变量也能够当做常量来应用,然而在理论应用的时候不倡议这么应用,因为在程序运行过程中有可能会将定义的变量扭转,变量并非不可扭转的。那有没有更好的定义常量的办法呢?有,这就须要应用预处理语句定义一个常量,这样定义的常量也被称为符号常量。语法是:#define NAME value

应用预处理语句,批改下面的例子:

#include<stdio.h>
#define PI 3.14159     // 应用预处理语句定义圆周率


int main(void)
{
    int r = 5;              // 圆的半径

    float area = PI * r * r;        // 计算圆的面积
    float circum = 2 * PI * r;      // 计算圆的周长

    printf("半径为 %d 的圆面积是: %.2f, 周长是: %.2f", r, area, circum);

    return 0;
}

预处理语句的作用是在编译的时候将 PI 替换为 3.14159,这样就达到了常量的作用了。预处理语句肯定要写在顶部,并且 PI 和 3.14159 之间是没有等号和完结时也没有分号的。后面也说了预处理语句是在编译时替换掉值,如果有了等号和分号,那么等号和分号也会变成要替换的值了。

还有一种办法是应用限定符 const 将变量限定为只读,批改下面的例子如下:

#include<stdio.h>

int main(void)
{
    const float pi = 3.14159;     // 应用限定符 const,定义常量圆周率
    int r = 5;                    // 圆的半径

    float area = pi * r * r;        // 计算圆的面积
    float circum = 2 * pi * r;      // 计算圆的周长

    printf("半径为 %d 的圆面积是: %.2f, 周长是: %.2f", r, area, circum);

    return 0;
}

应用 const 限定符定义的变量 pi 能够应用,能够应用 printf() 打印值,但就是无奈批改值。另外须要留神的是应用 const 限定符定义的是变量,不是常量。

输入输出

输入

在 C 语言中,通过 printf() 将内容输入到屏幕上,printf()也被称为格式化输入,能够让变量以某种格局输入到屏幕上,如 %d 为以整数的模式显示,%f 以浮点数的模式显示,下表列出了一些转换阐明和各自对应的输入类型:

转换阐明 输入
%a 浮点数、十六进制和 p 记数法
%A 浮点数、十六进制和 p 记数法
%c 单个字符
%d 有符号十进制整数
%e 浮点数,e 记数法
%E 浮点数,e 记数法
%f 浮点数,十进制记数法
%g 依据值的不同,主动抉择 %f 或 %e。%e 格局用于指数小于 - 4 或者大于或等于精度时
%G 依据值的不同,主动抉择 %f 或 %E。%E 格局用于指数小于 - 4 或者大于或等于精度时
%i 有符号十进制整数(与 %d 雷同)
%o 无符号八进制整数
%p 指针
%s 字符串
%u 无符号十进制整数
%x 无符号十六进制整数, 应用十六进制数 0f
%X 无符号十六进制整数, 应用十六进制数 0F
%% 打印一个百分号

一开始不须要全副都记住,只须要记住几个罕用的 (如:%d,%f,%c) 即可,其余的用到在看就能够了,用的多了就记住了。上面的例子是将一个整数以八进制和十六进制的模式显示:

#include<stdio.h>

int main(void)
{
    int num = 100; 

    printf("100 的八进制为 %o\n", num);        // 显示 num 的八进制
    printf("100 的八进制为 %#o\n", num);        // 显示 num 的八进制时,并在后面加上前缀
    printf("100 的十六进制为 %x\n", num);        // 显示 num 的十六进制
    printf("100 的十六进制为 %#x\n", num);    // 显示 num 的十六进制,并在后面加上前缀
    return 0;
}

运行后果:

能够通过 printf()函数配合 %o 和 %x 打印出数值的八进制模式和十六进制模式。# 只是为了显示前缀,八进制以 0 结尾,十六进制以 0x 结尾

有的读者可能不太理解什么是八进制和十六进制,那就简略的介绍一下。咱们日常说的 10,100,123 等数字,都是十进制,能够发现这些数字都是逢十进一,而八进制和十六进制同理,八进制就是逢八进一,十六进制是逢十六进一。有的读者就会问了,逢十六进一?那要怎么示意十以上的数呀?十六进制由 1 到 9 和 a 到 f(也能够是 A 到 F)组成,没错,a 到 f 别离示意 10 到 15。

参数与陷阱

在应用printf()scanf() 时须要确保转换阐明的数量、类型与前面的参数数量、类型匹配。因为 printf()scanf() 的参数是可变的,所以无奈查看出参数的个数和类型是否正确。

那如果参数个数不匹配会怎么呢?

#include<stdio.h>

int main(void)
{
    int num1 = 1;
    float num2 = 1.23;

    printf("%d %d %d\n", num1, num1, num1, num1);   // 参数太多
    printf("%d %d %d\n", num1);   // 参数太少
    printf("%d\n", num2);           // 类型不匹配


    return 0;
}

运行后果:

当应用 %d 打印一个浮点数时,不会将这个浮点数转换为 int 类型。在不同的平台下,短少参数或参数类型不匹配导致的后果会不雷同。

输出

在后面的两个数相加的例子中,两个相加的数是事后就设置好的,当要计算其余整数相加时,须要批改源文件并生成新的可执行文件,这就很麻烦,这是就能够让用户输出要进行计算的两个整数。

要想获取用户的输出能够应用 scanf() 进行接管,应用的办法与 printf() 类似,%d 示意要接管整数,%f 示意要接管一个浮点数。

批改程序:

#include<stdio.h>

int main(void)
{
    int num1, num2;     // 同时申明 num1 和 num2
    scanf("%d %d", &num1, &num2);       // 获取用户输出的 num1 和 num2 的值
    int sum = num1 + num2;   //num1 与 num2 相加后的后果赋值给 sum 变量

    printf("num1 + num2 = %d\n", sum);      // 将 sum 的值打印到屏幕

    return 0;
}

运行后果:

运行完程序,应该能够发现如果这是给程序员本人应用,那当然没有任何问题,然而给其他人应用,会呈现不晓得要干嘛的状况。所以应该在程序接管用户输出之前,通知用户要做什么,再次批改程序:

#include<stdio.h>

int main(void)
{
    int num1, num2;     // 同时申明 num1 和 num2
    printf("请输出两个须要相加的整数(例:12 34):");    // 提醒用户输出两个整数
    scanf("%d %d", &num1, &num2);       // 获取用户输出的 num1 和 num2 的值
    int sum = num1 + num2;               //num1 与 num2 相加后的后果赋值给 sum 变量

    printf("num1 + num2 = %d\n", sum);  // 将 sum 的值打印到屏幕

    return 0;
}

运行后果:

仔细的读者会发现在 num1 和 num2 的后面有一个 & 符号,那这个 & 符号示意的是什么意思呢?& 符号示意获取地址,整个语句就是将获取到的整数放入到 num1 和 num2 的地址中。

当读取的是根本的数据类型的值时须要应用 & 符号,而读取的是字符串时,不要应用 & 符号。

整数溢出

当一个整数类型超出了它能示意的最大值会呈现溢出,通过一个例子察看溢出后的后果

#include<stdio.h>

int main(void)
{
    int i = 2147483647;     // 定义一个有符号整数类型的变量 i 并初始化为最大值
    unsigned int j = 4294967295;       // 定义一个无符号整数类型的变量 j 并初始化为最大值

    printf("%d %d %d\n", i, i+1, i+2);
    printf("%u %u %u\n", j, j+1, j+2);
    return 0;
}

运行后果:

通过观察能够发现当一个数超过本身可能示意的最大值时,会从最小值开始。当产生溢出时零碎没有通知用户,所以在编程时须要留神。

char 类型

char 类型用于寄存字符(如:字母或标点符号),但 char 其实是整数类型,因为 char 实际上保留的是整数,而不是字符。有的读者就会有疑难了,存储整数,那要怎么晓得是哪个字符呢?在计算机中应用数字编码解决字符,即应用整数示意字符,在 ASCII 编码中 65 示意大写字母 ”A”,规范的 ASCII 的范畴是 0~127,齐全能够应用 char 类型进行存储

申明 char 类型变量

char 类型的变量在赋值时,值须要应用单引号括起来,如:char ch = 'A';,而不能是 char ch = A;。如果没有被单引号括起来,此时 A 示意一个变量名,而不是字符 A。

char 类型也能够间接保留整数,如 char ch = 65;,然而不倡议这样应用,这样应用须要零碎反对 ASCII 码,最好还是应用‘A’替换 65。

举个例子

用户输出一个字符,将这个字符对应的 ASCII 码打印在屏幕上:

#include<stdio.h>

int main(void)
{
    char ch;    // 定义变量 ch,用于接管用户输出

    printf("请输出一个字符(如:A):");
    scanf("%c", &ch);       // 接管用户输出的字符
    printf("%c 对应的整数为 %d\n", ch, ch);
    return 0;
}

运行后果:

转义字符

应用非凡的符号序列示意一些非凡的字符,这些符号序列就叫做转义序列,下表列出了转义序列及其含意

转义序列 含意
\a 警报(ANSI C)
\b 退格
\f 换页
\n 换行
\r 回车
\t 程度制表符(相当于 tab 键)
\v 垂直制表符
\\ 反斜杠()
\’ 单引号
\” 双引号
? 问号
\0oo 八进制值(oo 必须是无效八进制数)
\xhh 十六进制值(hh 必须是无效十六进制数)

通过一个例子更好的了解转义字符:

#include<stdio.h>

int main(void)
{
    float salary;

    printf("\aEnter your desired monthly salary:");
    printf("$_______\b\b\b\b\b\b\b");
    scanf("%f", &salary);
    printf("\n\t$%.2f a month is $%.2f a year.", salary, salary * 12.0);
    printf("\rGee!\n");
    return 0;
}

运行后果:

解析:

在程序的第 7 行 printf("\aEnter your desired monthly salary:"); 中的 \a 会收回警报的声音(是否收回警报取决于硬件,有可能不会收回警报)

接着第 8 行的 printf("$_______\b\b\b\b\b\b\b"); 先将 $_______打印进去呢,接着应用 \b 挪动光标,使光标紧跟 $ 符

在第 10 行的 printf("\n\t$%.2f a month is $%.2f a year.", salary, salary * 12.0); 首先是 \n 进行换行,接着是制表符 \t 使前面的内容缩进。光标停留在最初的点那里(.),如下图:

在第 11 行的 printf("\rGee!\n"); \r 将光标挪动到以后行是起始地位,再打印内容,最初的 \n 换行

reference

《C Primer Plus》(第六版)

大话 C 语言变量和数据类型 —C 语言中文网

C 语言转义字符 —C 语言中文网

C 数据类型 — 菜鸟教程

C 变量 — 菜鸟教程

C 常量 — 菜鸟教程

退出移动版