变量与常量
为了可能更加不便的应用数据,程序员会将在程序运行期间会扭转或赋值的数据应用变量进行保留。常量则是事后定义好,在程序运行期间不会扭转的固定值
变量和常量就如同是一个盒子,能够用来装货色(数据)。在计算机中,数据是寄存在内存中的,存放数据的内存空间程序员为了不便当前的应用,都会起一个好记的名字。这个名称也由字母、数字和下划线组成,必须要以字母和下划线结尾。因为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 常量---菜鸟教程