c_basic_1_datatype

2023-12-27

数据类型

1、常量与变量

1.1、关键字

C关键字共有32个

1)数据类型关键字12个:

char、short、int、long(long long)、float、double、unsigned、signed、struct、union、enum、void

2)控制语句关键字12个:

if、else、switch、case、default、break、for、do,while、continue、goto、return

3)存储类关键字5个:

auto、extern、register、static、const

4)其他关键字3个:

sizeof、typedef、volatile(防止编译器优化)

1.2、数据类型

数据类型的作用:编译器预算对象(变量)分配的内存空间大小

  • 数据类型:
    • 基本类型
      • 整型:int、short、long
      • 字符型:char
      • 实型(浮点型):float(单精度实型)、double(双精度实型)
    • 构造类型
      • 数组类型
      • 结构体:struct
      • 联合类型:union
      • 枚举类型:enum
    • 指针类型: (char *、 int *、int **等)

1.3、常量

  • 在程序运行过程中,其值不能被改变的量
  • 常量一般出现在表达式或赋值语句中

定义常量的方式:

const 数据类型 常量名=; (在C语言中不安全,建议使用宏,在C++中安全)
#define 常量名 值

1.4、变量

  • 在程序运行过程中,其值可以被改变的量

  • 占位符,%f 表示输出一个浮点型float,默认保留6位小数 占位符,%lf 表示输出一个浮点型double 占位符,%.2f 表示输出一个浮点型float,保留两位小数,在C中会四舍五入,在C++中不会四舍五入

    占位符,%.2lf 表示输出一个浮点型float,保留两位小数,在C中会四舍五入,在C++中不会四舍五入

变量定义格式:

数据类型 变量名=;
#include<stdio.h>

//宏定义
#define PI 3.14159
int main()
{
	//const double pi = 3.14159265354;
	float r = 2;
	double s = PI * r * r;
	double l = 2 * PI * r;

	//占位符,%f 表示输出一个浮点型float,默认保留6位小数
	//占位符,%lf 表示输出一个浮点型double
	//占位符,%.2f 表示输出一个浮点型float,保留两位小数,在C中会四舍五入,在C++中不会四舍五入

	printf("圆的周长:%lf\n圆的面积:%.2lf\n", l, s);
	return 0;
}

注:在定义局部变量可以在数据类型前面加修饰 auto, 也可以不加

1.5、标识符

1)命名规则:

  • 不能使用关键字
  • 允许使用字母、数字和下划线的组合
  • 不允许以数字开头
  • 标识符字母区分大小写
  • 见名知意

2、整型:int

2.1、整型变量的定义和输出

打印格式 含义
%d 输出一个有符号的十进制 int 类型
%o 八进制 int 类型
%x 十六进制 int 类型,字母以小写形式输出
%X 十六进制 int 类型,字母以大写形式输出
%u 输出一个无符号的十进制 int 类型
#include<stdio.h>

int main0301()
{
	//无符号 unsigned;有符号 signed(可以省略,默认都是有符号的)
	//int a = -10;
	unsigned int b = -10;

	//%u 占位符,输出一个无符号的十进制 int 类型
	printf("%u\n", b);
	return 0;

}

int main(void)
{
	/*
	//进制相关的问题
	//二进制(0-1)、八进制(0-7)、十六进制(0-9 A-F)
	int a = 10;
	printf("%d\n", a);

	//%x 占位符,输出一个八进制 int 类型
	printf("%x\n", a);
	printf("%X\n", a);

	//%u 占位符,输出一个十六进制 int 类型
	printf("%o\n", a);
	*/


	//定义八进制数据,以0开头
	int a = 0123;

	//定义16进制数据,以0x开头
	int b = 0xabcdef;

	printf("%d %d\n", a, b);

	//计算机定义数据是,不可以直接定义二进制

	return 0;
}

2.2、整型变量的输入

1)VS的C4996错误

scanf 引起的安全警告问题

由于微软在VS中不建议使用C的传统库函数 scanf,srtcpy,sprintf等,所以直接使用这些库函数会提示C4996错误。VS建议使用带_s的函数,如scanf_s,strcpy_s等函数,这些函数不是编撰C函数。

要继续使用此函数,要在源文件中添加宏来避免这个错误:

#define _CRT_SECURE_NO_WARNINGS			# 这个宏放在程序第一行,其他位置依然会报错
#pragma warning(disable:4996)			# 或者使用这和
  • 由于用户输入的可能不是期望的类型,但是依然按照期望的类型进行处理了,最终导致出错,因此是不安全的

2.3 short、int、long、long long

数据类型 占用空间
short 2字节
int 4字节
long windows为4字节;linux下32位为4字节,64位为8字节
long long 8字节

3、sizeof 关键字

计算一个数据类型的大小,单位为字节。返回值为 size_t,在32位系统下是unsigned int,是一个无符号的整数。

sizeof(数据类型)	//或者		
sizeof(变量名)

注:整型数据在内存中的占据内存大小与操作系统有关,但是:

short<=int <=long<long long

当一个小的类型赋值给大的类型,不会有丢失,但是反过来会有丢失

4、字符型

4.1、字符型变量的输入输出

char 存储一个字符 占用一个字节 单引号’‘

字符型存储时,存放的是字符对应的ASCII码,实际上字符型是一个一字节的整型数据。

  • 字符型变量
char ch='a';
  • 打印字符型变量
printf("%c\n",ch);
  • 打印字符对应的十进制
printf("%d\n",ch);
  • ASCII码:

空格:32

‘0’:48

‘A’:65

‘a’:97

  • 字符型也可以进行加、减运算
char ch1='a';
char ch2='A';
printf("%d\n",ch1-ch2);

  • 小写字母转大写字母,减32;大写字母转小写字母,加32

4.2、转义字符

转义字符 含义 ASCII码
\a 警报 007
\b 退格 008
\f 换页 012
\n 换行 010
\r 回车 013
\t 水平制表符 009
\v 竖直制表符 011
\\ 反斜线 092
\' 单引号 039
\" 双引号 034
\? 问好 063
\0 数字0 000
\ddd 8进制转义字符,d的范围0-7 3位八进制
\xhh 16进制转义字符,h的范围0-9,a-f,A-F 3位十六进制

打印%也需要进行转义:\%

5、实型(浮点型):float,double

  • double类型比float表示的浮点型精度更高。
  • 由于存储单元有限,因此浮点型的表示精度也是有限的,存在误差。
  • 占位符 %lf 表示double型的输出,但是使用 %f 也可以

5.1、sizeof 字节大小

  • float:4字节
  • double:8字节

浮点型在内存中的存储分为三部分:

  • 符号位
  • 指数为
  • 小数位

占位符 %p 以无符号十六进制显示内存的地址:

int a=10;
float b=3.14;
printf("%p\n",&a);
printf("%p\n",&b);

大小端对齐存储

5.2、以科学计数法表示浮点型数据

float a=3.2e2f;

float b=3.2e-2f;

float c=3210.454;
printf("%e\n",c);

float d=0.123456;
printf("%e\n",d);

6、进制

x进制就是逢x进一。

6.1、二进制

基数为2,逢二进一,借一当二。

数据在计算机中主要是以补码的形式存储的。

1)十进制转二进制

除二反序取余法

2)二进制转十进制

权值法:将一个二进制从末尾开始乘以二的n次幂,n从0开始

1010 $\rightarrow$ 0 * 2^0+1 * 2^1+0 * 2^2+1 * 2^3=10

3)十进制转八进制

除八反序取余法

4)八进制转十进制

权值法:将一个八进制从末尾开始乘以八的n次幂,n从0开始

5)十进制转十六进制

除十六反序取余法

6)十六进制转十进制

权值法:将一个十六进制从末尾开始乘以十六的n次幂,n从0开始

7)二进制和八进制、十六进制之间的转换

  • 8421法则:二进制转十进制,从右往左,分别对应1,2,4,8,……
  • 二进制转八进制:二进制从右往左,三位一组,将三位二进制转换成一位八进制
  • 八进制转二进制:一位八进制转换成三位二进制
  • 二进制转十六进制:二进制从右往左,四位一组,将四位二进制转换成一位十六进制
  • 十六进制转二进制:一位十六进制转换成四位二进制

7、计算机内数据的存储方式

7.1、小数转二进制

十进制小数转二进制,小数部分和2相乘,取整数,不足1取0,每次相乘都是小数部分,顺序看取整后的数就是转化后的结果

例如:0.432

0.432*2=(0)(0.864) * 2=(1)(0.728) * 2=(1)(0.456)

由于0.432三位小数,因此结果就只需取三位,对应的二进制结果为0.011

7.2、内存单位

术语 含义
bit(比特) 一个二进制的一位
Byte(字节) 一个字节为8位二进制,计算机中最小的存储单元

7.3、原码

原码:数字的二进制形式

  • 最高位作为符号位,0表示正,1表示负
  • 其他数值部分就是数值本身绝对的二进制数
  • 负数的原码是在其绝对值的原码的基础上,符号位为1

7.4、反码

  • 对于 正数,反码与原码相同
  • 对于负数,符号位不变,其他部分按位取反

7.5、补码

在计算机系统中,数值一律用补码来存储

  • 对于正数,原码、反码、补码相同
  • 对于负数,其补码为反码加1
  • 补码符号位不动,其他位取反,最后整个数加1,得到原码

补码运算的优点:

  • 统一了0的编码
  • 将符号位和其他位统一处理
  • 将减法运算转换为加法运算
  • 两个用补码表示的数相加时,如果最高位(符号位)有进位,则进位直接舍弃

零在计算机中的存储方式:0000 0000

7.6、有符号数和无符号数的取值范围

有符号:

数据存储时,将-0对应的区间值,设为最小的负数,例如8位,就是-128

有符号字符型取值范围:[-2^7, 2^7-1]

signed int 32bit:[-2^31, 2^31-1]

long long 64bit:[-2^61, 2^61-1]

short 2bit:[2^-15, 2^15-1]

long 32bit:[-2^31, 2^31-1]

无符号:

unsigned char:[0, 2^8-1]

unsigned int:[0, 2^32-1]

unsigned long:[0, 2^32-1]

unsigned short:[0, 2^16-1]

8、数据溢出

char ch=127;
ch+=2;
printf("%d\n",ch);		//-127
  • 当超过一个数据类型能够存放的最大范围时,数值会溢出。
  • 有符号位最高位溢出:符号位溢出会导致数的正负发生变化,最高位溢出会导致最高位丢失

9、类型限定

限定符 说明
extern 声明一个变量,extern声明的变量没有建立存储空间。extern int a; //变量a在定义的时候没有创建存储空间,告诉编译器有这么一个变量,但是没有告诉内存
const 定义一个常量,常量的值不能修改。const int a=10;
volatile 防止编译器优化代码,平时不会使用,只有实现特定功能的代码的时候会使用,防止因为编译器的优化而使代码在某些情况下出错
register 定义寄存器变量,提高效率,register 是建议型的指令,而不是命令型的指令,如果CPU 有空闲的寄存器,那么 register 就生效,如果没有空闲的寄存器,那么 register 就无效。

计算机中的变量在存储的时候分三步:1)声明;2)定义;3)使用

10、字符串的格式化输入和输出

10.1、字符串常量

  • 字符串是内存中一段连续的 char 空间,以 ‘\0’ 结尾
  • 字符串常量是由双引号括起来的字符序列,如 “china”
  • 字符串常量和字符常量不同:
    • “a” 为字符串常量,编译器会自动在末尾添加一个结束标志位 ‘\0’,即 “a” 包含两个字符 ‘a’ 和 ‘\0’,占两个字节空间
    • ‘a’ 为字符常量,占一个字节空间
  • 占位符 %s 表示输出一个字符串,遇到 \0 停止,例如:
char *a="hello \0 world"
printf("%s\n",a);		//输出为 hello

char *b="hello world"
printf("%s\n",b);		//输出为 hello world

char *c[11]="hello world"
printf("%s\n",c);		//输出为 hello world83w90mfi3	由于只有11个字节位置,没有空间存储结束标志符 \0 ,%s 在输出的时候找不到结束位置,就会一直往后读取内存,直到遇到 \0 为止,额外输出的内容是不确定的

10.2、printf 函数和 putchar 函数

printf 是输出一个字符串,putchar 是输出一个 char

1)printf

打印格式 对应数据类型 含义
%d int 接受整数值并将它表示为有符号的十进制整数
%hd short int 短整型数
%hu unsigned short 无符号短整数
%o unsigned int 无符号八进制
%u unsigned int 无符号十进制
%x, %X unsigned int 无符号十六进制,%x 对应 abcdef,%X 对应 ABCDEF
%f float 单精度浮点数
%lf double 双精度浮点型
%e, %E double 科学计数法表示的数,e 和 E 分别对应输出时的 e 的形式
%c char 字符型,可以把输入的数字按照ASCII码转换为相应的字符
%s char * 字符串,输出字符串中的字符直至遇到字符串中的空字符(\0)为止
%p void * 以十六进制形式输出指针
%% % 输出一个百分号

printf 附加格式:

字符 含义
l(字母l) 附加在d,u,x,o前面,表示长整数
- 左对齐
m(代表一个整数) 数据最小宽度
0(数字0) 将输出的前面补上0直到占满指定列宽为止,不可以搭配使用-
m.n(代表一个整数) m指定域宽,即对应的输出项在输出设备上所占的字符数,n值精度,用于说明输出的实型数的小数位数,对于数值型来说,未指定n时,默认的精度 n=6
int a=10;
printf("%d\n",a);		//10
printf("===%-5d===\n",a);		//===10   ===
printf("===%5d===\n",a);		//===   10===	默认右对齐
printf("===%05d===\n",a);		//===00010===

int b=123456;
printf("===%05d===\n",b);		//===123456===	数据的长度大于指定的域宽,就直接输出,若小于,则使用指定字符填充

float c=3.14;
printf("%3.2f\n",c);			//3.14
printf("%===7.2f===\n",c);		//===   3.14===	m表示正体的宽度
printf("%===07.2f===\n",c);		//===0003.14===	m表示正体的宽度
printf("%===-7.2f===\n",c);		//===3.14   ===	m表示正体的宽度

2)putchar

char ch='a';
//输出字符
printf("%c\n",a);		//a

//putchar
putchar(ch);			//a
putchar('B');			//B
putchar(97);			//a

//输出转义字符
putchar('\n');			//输出一个换行符
  • putchar 输出字符,可以是变量,字符,数字(0-127),转义字符

10.3、scanf 函数和 getchar 函数

  • getchar 是从标准输入设备读取一个 char
  • scanf 同过 % 转义的方式可以得到用户通过标准输入设备输入的数据

1)scanf

char ch;
scanf("%c",&ch);
putchar(ch);

int a,b;
scanf("%d%d",&a,&b);			//有多个占位符的时候,输入通过空格或者换行来进行分割,这里可以输入12 34,也可以输入12\n34
scanf("%d,%d",&a,&b);			//也可以使用特定的分隔符,例如使用逗号,输入格式为:12,34。但是不能使用 \n 作为分隔符,因为使用 \n 会导致输入无法终止
printf("%d\t%d\n",a,b);

scanf("%3d,%d",&a,&b);			//使用域宽限制,可以对整型的输入进行限制,例如这里输入:123456
printf("%d\t%d\n",a,b);			//输出结果为:123        456

2)getchar

char ch;

//接收键盘获取字符
ch=getchar();		//输入:b
putchar(ch);		//输出:b

ch=getchar();		//输入:abc
putchar(ch);		//输出:a	putchar只能输入一个字符

//在程序最后添加 getchar() ,可以使窗口停留等待,达到和 system("pause")类似的效果
getchar();