C语言基础 数据类型,变量,常量

一.基本数据类型

以下所写的占用的存储空间在不同编译器中可能不同,标注的只是通常的情况

//数据类型关键字:
int:整型                            signed(C90中新增):有符号的
long:增长                           void(C90中新增):空值
short:缩短                          _Bool(C99中新增):布尔值
unsigned:无符号的(仅有正数)          _Complex(C99中新增):复数
char:字符                           _Imaginary(C99中新增):虚数
float:(单精度)浮点型
double:双精度浮点型

1.整型:

用于储存整数,分为:
1.短整型(short intshort):占用2B(不能多于int)
2.整型(int):占用4B
3.长整型(long intlong):占用4B(不能少于int)
4.16进制或8进制整数:
  ①在前面加0x或0X表示16进制数,0x10表示10进制下的16
  ②在前面加0表示8进制数,010表示10进制下的8
5.long long intlong long:C99加入;占用至少8B(不能少于long int)
6.unsigned intunsigned:无符号的整型
  可以表示比int允许的更大的数:16unsigned取值范围是0~65535,int-32768~32767
7.unsigned long intunsigned long:C90加入
8.unsigned short intunsigned short:C90加入
9.unsigned long long intunsigned long long:C99加入
10.在任何有符号类型前加signed,可强调有符号的意图:shortsigned short相同
11._Bool:布尔值,即true和false;实际上也是1种整数类型,0表示false,1表示true,但原则上仅占用1位
  参见 C语言细节.流程控制.2 部分

注意:
1.有些编译器无法识别5/7/8/9
2.优先使用unsigned类型以表示更大的数
3.较大的类型会降低运算速度,尽量避免使用
  • 整型存储方式:

在这里插入图片描述
2.浮点型:

用于储存小数,分为:
1.单精度浮点数(float):占用4B,7位有效数字
2.双精度浮点数(double):占用8B,15~16位有效数字
3.long double:精度不低于double
  • 存储问题:
1.浮点数的存储可能存在误差
比如float x=6.234,实际存储的可能是6.239999
因此,判断float类型的变量x的值是否为0的标准方法是:
if (abs(x)<= 1e-6)//abs()表示取绝对值
    printf("是");
else
    printf("不是");
判断double类型的变量y的值是否为0的标准方法是:
if (abs(y)<= 1e-15)
    printf("是");
else
    printf("不是");
//float的精度误差为1e-6,double的精度误差为1e-15 

2.对于一些算术运算(2个大数相减),浮点数损失的精度更多

3.浮点数运算比整数运算慢,虽然现在这个差距已经缩小了
  • 浮点型的存储方式:

在这里插入图片描述

:在计算机内部使用的是二进制和2的幂进行存储,而不是十进制和10的幂

3.字符型:

字符(char):用于储存单个字符,使用' '括起,占用1B

#注意:
1.C语言中没有可以直接存储多个字符的数据类型,需要通过字符数组来完成该功能(参见 C语言基础.数组.六 部分)
2.char类型不得使用" "扩起,因为这样内部至少有2个字符("A"表示"A\0")
  不过好像可以通过编译,但警告如下:
    [Warning] initialization makes integer from pointer without a cast
  而且下述命令打印不出来变量值:
    char m="a";
	printf("%c",m);//结果:  (没错,什么都没有)
3.''不合法,' '合法
4.字符变量实际上存储的是该字符相应的ASCII码,因此可以像整数一样进行运算
char ch;
scanf("%c",&ch);//输入:s
//char ch=getchar();//相当于上面2行
putchar(ch+1);//结果:t
printf("\n");
putchar(ch/2);//结果:9
putchar('\n');
putchar(ch-ch/10);//结果:h
printf("\n");
printf("%c\n",ch-2);//结果:q

二.复合数据类型
1.结构体:

参见 C语言基础.结构体 部分

2.枚举(Enumerated Type)
(1)什么是枚举:

定义:列出某个有穷集的所有成员
即:把某个事物所有可能的取值全部列举出来

(2)语法:

//定义1个枚举:这里是定义了1个数据类型(或模板),而不是定义了1个变量
enum <enum_name> {
    <name0>[=<val0>],<name1>[=<val1>]...
    //注意:结尾没有分号(;)
};//注意:这里有分号(;)
  //参数说明:
    enum_name:枚举的名称
    name:该枚举所有可能的成员的名称(这些符号常量称为"枚举符"(Enumerator))
      //这里的名称可以是任意值(如为Monday),不一定是char/int...等C语言中的数据类型
    val:该枚举所有可能的成员的值
      //本质上存储和处理的是这些值,但赋值时不能用相应的值来代替成员名称
      //这些可能的值默认会被从0开始按顺序编号(val0为0,val1为1...)
      //指定某成员的值为x,则之后的值会从x+1开始按顺序编号,直到下1个被指定了值的成员

//定义1个枚举变量:这里才定义了1个变量
enum <enum_name> <evar>[=<val>];
  //参数说明:enum_name同上
    evar:变量名
    val:该变量的值
      //此处的值必需在定义枚举时列举的值(val0,val1...)中
      //而且不能使用该值的编号代替该值

//实例:
#include <stdio.h>

enum WeekDay {
	Monday,Tuesday,Wednesday,Thursday,Friday=10,Saturday,Sunday
};

void f(enum WeekDay i) {
    switch (i) {
        case 0:printf("Monday\n");break;
        case 1:printf("Tuesday\n");break;
        case 2:printf("Wednesday\n");break;
        case 3:printf("Thursday\n");break;
        case 10:printf("Friday\n");break;
        case 11:printf("Saturday\n");break;
        case 12:printf("Sunday\n");break;//结果:Sunday
    }
}

int main(void) {
	enum WeekDay day1=Wednesday,day2=Sunday;
	printf("%d\n",day1);//结果:2//因为Wednesday是WeekDay中的第3个选项
	//把枚举变量当作int输出,实际上输出的是枚举变量的值的编号
	printf("%d\n",)//结果:12
	f(day2);//day2实际上是按其值(Sunday)的编号(12)来被处理的
	return 0;
}

(3)枚举的优缺点:

优点:代码更安全;提高了代码的可读性
缺点:书写麻烦

(4)自增/减:

C语言允许对枚举变量使用自增/减运算符:
  //不过C++不允许,所以如果希望兼容C++,就不能使用自增/减运算符
#include <stdio.h>

enum colors {
	red,yellow,green,black
};

int main(void) {
	enum colors color;
	char * acolors[]={"red","yellow","green","black"};
	for (color=red;color<black;color++) {
		printf("%s ",acolors[color]);
	}
    return 0;
}
//结果:
red yellow green

3.联合

参见 C语言细节.其他数据类型.一 部分

三.变量
1.什么是变量:

变量是那些在程序运行过程中可以改变的量

变量指向某块内存空间,这块内存空间中保存有该变量存储的数据
也就是说,变量的本质就是内存中的1段存储空间
程序一旦运行完毕,为其中所有变量分配的内存空间都会被释放掉
释放指这块内存空间可被分配给其他变量,而非清除内存中的遗留数据
变量类型同数据类型

2.变量名:

变量名是1种标识符

//标识符命名规则:
1.只能由字母/数字/下划线(_)组成,数字不能在首位
  //在C99/C11中根据通用字符名(UCN)机制添加了扩展字符集,其中包含了更多字符
2.不能用C语言的关键字作为变量名
3.但编译器只识别标识符名的前63个字符;外部标识符只允许31个字符
  //如果2个标识符名在63个字符后才有区别,标准并未规定,结果取决于编译器
  //C90仅允许6个字符;旧式编译器通常只允许8个字符
4.区分大小写
5.标识符名应尽量有意义(非强制)

//注意:
1个变量名在1个程序中只能被定义1:
int a=45;
int a=9;
//报错:
[Error] redefinition of 'a'
[Note] previous definition of 'a' was here

3.声明变量:

//注意:每条命令后面都需要加";"

//声明变量:声明为变量创建并标记内存空间
<type> <var>[=<val>];
  //这种只存储单个值的变量有时称为"标量变量"(Scalar Variable)
  //更详细的规则参见 C语言细节.其他数据类型.四 部分
  //参数说明:
    type:指定数据类型
    var:指定变量名
    val:指定变量值(这个值本身是1个常量)

//也可以把创建和赋值分开写:
<type> <var>;
<var>=<val>;

//说明:
1.C99允许在任何位置定义变量
int price=0;
printf("请输入金额(元):");
scanf("%d",&price);
int change=100-price;
printf("找零为%d元\n",change);
2.ANSI C要求必须在程序开头定义所有变量
int price=0;
int change=0;
printf("请输入金额(元):");
scanf("%d",&price);
change=100-price;
printf("找零为%d元\n",change);
3.变量必须先被定义,然后才能使用,如果定义位置在使用位置后,会找不到该变量
4.1个变量名不能在1个作用域内只能使用1//实例:
int i=3;
  等价于:int i;i=3;
int i,j;i=3;j=5;
  等价于:int i;int j;i=3;j=5;
int i,j=3;
  等价于:int i;int j;j=3;
int i=3,j=5;
  等价于:int i;int j;i=3;j=5;
int i,j;i=j=5
  等价于:int i;int j;i=5;j=5

4.变量的初始化:

初始化的意思就是赋初值,以覆盖内存中的垃圾值(即上1个占用这块内存空间的变量的遗留值)
如果不初始化,变量的值是0(int)/空格(char)/0.000000(float)或为垃圾值或自动赋1个很大的值

在C语言中,初始化是在声明变量时完成的,:
int a=11;
int b=1,c=2;
int d,e=0;//注意:这里仅初始化了e

在这里插入图片描述
四.常量

常量是固定值,在程序执行期间不会改变,又叫字面量
常量就像是常规的变量,不过其值在定义后不能修改
常量分为整数,浮点数,字符

1.表示方法:

整数:
  10进制:普通写法,11
  16进制:前面加0x/0X,0x1F表示31
  8进制:前面加0(加数字零,不是O),010表示8
  会按int-unsigned-long-unsigned long-long long-unsigned long long尝试存储
  要指定作为某类型存储,可在值最后加后缀(10/8/16进制下均可),12L/12ULL
浮点数:
  普通写法:94.23
  科学计数法:1.23e3表示1230,3.1e-1表示0.31
  可在值最后加后缀以指定类型,默认是double,加L/l是long double,加F/f是float
字符:
  //所有用" "扩起的内容默认都会被在结尾补上1个结束符'\0'
  //在创建常量时,二者的type都是char
  单个字符:' '扩起,'a'
    注意:'ab'错误
  多个字符(字符串;str):" "扩起,"ale"
    注意:"a"正确,表示"a\0"
注意:输入不符合数据类型的值不一定报错,:int a=1.2只会导致警告

2.声明常量:

//方法1:将<var>定义成1个符号,此时<var>只是<val>的别名
常量名通常全部大写(非强制)
这样定义的常量称为"符号常量"(Symbolic Constant)"明示常量"(Manifest Constant)"宏常量"(Macro-Defined Constant)
程序中所有的<var>都会在编译时被替换为<val>,该过程称为"编译时替换"(Compile-Time Substitution)
#define <var> <val>;
  //参数说明:
    var:指定常量名
    val:指定常量值(这个值本身也是1个常量,即字面量)
      //可以是整数/浮点数/字符/字符串/表达式
  //实例:
    #define Pi 3.1415926f;

//方法2:将<var>定义成1个变量并告诉编译器其值固定,如果试图修改其值,则编译时会报错
这种本质上还是变量,称为"常变量";常变量名统称全部小写
const <type> <var> <val>;
  //参数说明:
    type:指定数据类型
    var:指定常量名
    val:指定常量值
  //实例:
    const float pi 3.1415926f;

3.常量/变量的二进制代码:

·整数以补码的形式存储,实数按IEEE754标准存储
·字符按ASCII转换成整数,转换后的整数再以补码形式存储

五.数据类型的转换
1.不同类型数据间的相互赋值:

1.字符和整数间可按ASCII互相转换
2.整数间,浮点数间,整数和浮点数间也可以互相转换,不过存在溢出的风险

通常,在语句和表达式中应使用类型相同的变量和常量
但是,如果使用混合类型,C语言会进行自动类型转换,但这有一定的危险性

1.当类型转换出现在表达式时,unsignedsignedchar/short会被自动转换成int,如有必要则
会被转换成unsigned int(如果shortint大小相同,unsigned short就比int,这种情况下,
unsigned short会被转换成unsigned int);在K&R那时的C中,f1oat会被自动转换成double(目
前的C则不是);由于都是从较小类型转换为较大类型,所以这些转换被称为升级(Promotion)

2.涉及2种类型的运算,2个值会被分别转换成2种类型的更高级别

3.类型的级别从高至低依次是long double,double,float,unsigned long long,long long
unsigned long,long,unsigned int,int;例外是,longint大小相同时,unsigned intlong的级别高;之所以没有列出shortchar,是因为它们已经被升级到int/unsigned int

4.在赋值表达式语句中,计算结果会被转换成被赋值变量的类型,这个过程可能导致类型升级或降
级(Demotion);降级就是指转换成更低级别的类型

5.作为函数参数传递时,char/short被转换成int,float被转换成double

int i=45;
long j=102345;
i=j;
printf("%ld,%d\n",i,j);//结果:102345,102345
float x=6.6;
double y=8.8;
printf("%f,%lf\n",x,y);//结果:6.600000,8.800000
int a=45;
int b=2147483649;//会发生溢出
printf("%d,%d\n",a,b);//结果:45,-2147483647
char m="a";
m=a;
printf("%c",m);//结果:-
char ch='A';
printf("%d\n",ch);//结果:65
char c=65;
printf("%c\n",c);//结果:A

注意:升级通常不会有问题,但降级可能导致溢出

//

如果待转换的值和目标类型不符,结果将取决于转换涉及的类型,规则如下:
1.目标类型是无符号整型且待赋的值是整数时,额外的位将被忽略
如,如果目标类型是8unsigned char,待赋的值是原始值求模256

2.如果目标类型是有符号整型且待赋的值是整数,结果因实现而异

3.如果目标类型是整型且待赋的值是浮点数,该行为是未定义的

4.当浮点类型被降级为整数类型时,原来的浮点值会被截断
如23.1223.99都会被截断为23,-23.5会被截断为-23

2.强制类型转换运算符(Cast Operator):

//语法:
(<type>)(<var>)
  //参数说明:
    type:指定要转换成什么类型
    var:要转换的变量;可为变量名或变量值

//实例:
printf("%c\n",(char)(39));//结果:'
printf("%d\n",(int)('A'));//结果:65//即int→char按ASCII转换
printf("%d\n",(int)(3.7+1.2));//结果:4//即float→int会截断到整数位
printf("%f\n",(float)(3));//结果:3.000000//即int→float会补0
printf("%c\n",(char)(65.78));//结果:A//即float→char会先截断再按ASCII转换(相当于(char)((int)(<float>)))

int i;
float sum=0.0;
for (i=1;i<=100;i++) {
    printf("%d\n",1/i);//结果:1 0 ... 0
    printf("%f\n",1/(float)(i));//结果:1.000000 0.500000 ... 0.010000
    printf("%f\n",(float)/(1/i));//结果:1.000000 0.000000 ... 0.000000
	sum+=1/(float)(i);
	//相当于:sum+=1.0/i;
	printf("%f\n",sum);//结果:1.000000 1.500000 ... 5.187378
}
printf("%f\n",sum);//结果:5.187378

六.变量的作用域和存储方式
1.变量按作用域分类:

①全局变量:在所有函数外部定义的变量
  作用域默认是从定义的位置到程序结尾

②局部变量:在函数内部定义的变量和函数的形参
  作用域只限于当前语句块(不包括上级语句块,也不包括下级语句块)main()中定义的变量也是局部变量;main()中也不能使用其它函数中定义的变量—main()与其它函数平权
  可以在不同函数中使用相同的变量名,它们表示不同的数据,分配不同的内存,互不干扰
  实参给形参传值的过程也就是给局部变量赋值的过程
  如果局部变量和全局变量同名,全局变量在该作用域中会被局部变量覆盖

//实例:
#include <stdio.h>
#include <math.h>
void qqq(int i);
int j=33,r=22222;//全局变量
int main(void) {
	int i=12;//局部变量
	qqq(i);//传入局部变量
	return 0;
}
void qqq(i) {//局部变量
	printf("%d\n",i);//结果:12//使用局部变量
	//int j=2233;//加上这行结果是2233//局部变量
	void ppp(j) {//局部变量
		printf("%d\n",j);//结果:33//使用局部变量
	}
	ppp(j);//传入全局变量;如果加上int j=2233那行,则此次传入的是局部变量
}
void ttt(int k) {//局部变量
    printf("%d,%d\n",k,r);//使用局部变量和全局变量
}

2.变量按存储方式分类:

①静态变量
②自动变量
③寄存器变量

七.关键字与保留标识符
1.关键字:

以下既包括C89中的关键字,也包括C90/C99/C11中新增的关键字
autobreakcasecharconstcontinue
defaultdodoubleelseenumextern
floatforgotoifinlineint
longregisterrestrictreturnshortsigned
sizeofstaticstructswitchtypedefunion
unsignedvoidvolatilewhile_Alignas_Alignof
_Atomic_Bool_Complex_Generic_Imaginary_Noreturn
_Static_assert_Thread_local
//使用关键字作为标识符会报错:
#include <stdio.h>

int main(void) {
	int return=11;
	return 0;
}
//报错:[Error] expected identifier or '(' before 'return'

2.保留标识符(Reserved Identifier):

还有一些保留标识符,已被C语言使用或保留了使用权,如printf
使用保留标识符作为标识符不会直接报错,但可能导致其他问题

//实例:
#include <stdio.h>

int main(void) {
	int printf=11;
	printf("AAA\n");//注释掉该行即可编译通过
	return 0;
}
//报错:[Error] called object 'printf' is not a function or function pointer
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值