数据类型
总览图
作用
数据类型,也即变量类型,定义了变量所占内存空间规模大小的一个单位模板,它能够方便地让开发者对数据进行定位处理。
本质
数据类型的本质为一段内存地址的别名,表示为变量的起始内存地址+偏移量(数据长度)。
表示方式
基本数据类型:
short、int、long、char、float、double
自定义类型:
typedfe 关键字定义
#define宏定义
typedef char* PCHAR;//typedef用法
#define PINT int*//#define用法
int main()
{
PCHAR p1,p2;
char c1='1',c2='2';
PINT p3,p4;//宏替换后代码为int*p3,p4;而定义两个指针的方式为int*p3,*p4;
int n1=1,n2=2;
p1=&c1;//p1为PCHAR类型 即char*
p2=&c2;//p2为PCHAR类型 即char*
p3=&n1;//p3为int* 类型 n1为int
p4=&n2;//p4为int 类型 n2为int 提示警告int与int*的间接级别不同
return 0;
}
//#define只是替换、无别名概念
enum
//定义一系列的常量,常与switch搭配使用
enum Color
{
red=0,//默认是从0开始
yellow,//后一值为前一值+1
blue
}
struct结构体
#include<stdio.h>
struct Goods
{
int price;
int id;
char name[20];
char illustrate[20];
char madeof[20];
};
struct SoftArray
{
int len;
int array[];//占位符 不占用内存大小
};
int main()
{
struct Goods item;
item.price = 100;
item.id = 1;
//item.name="红糖水";
//字符串是存储在常量区的,也即"红糖水"实际上代表的是一个指向常量区的指针
//数组名是一个指针常量,不可修改的它的指向,对于字符串应采取库函数
strcpy(item.name, "红糖水");
//====================柔性数组=====================================
int len = 0;
printf("请输入数组大小");
scanf("%d", &len);
struct SoftArray *sa = malloc(sizeof(struct SoftArray) + sizeof(int)*len);
sa->array[0] = 'q';
sa->array[1] = 'd';
sa->array[2] = '0';
printf("sa:%p,&sa->len:%p,sa->array:%p,sa->array:%s,sizeof(struct SoftArray):%d", sa, &sa->len, sa->array, sa->array, sizeof(struct SoftArray));
//输入20
//输出sa:00857F30,&sa->len:00857F30,sa->array:00857F34,sa->array:q,sizeof(struct SoftArray):4
free(sa);
sa = NULL;//是为了误用空指针sa的时候触发空指针异常,否则误用sa的未定义行为是很难调试的
return 0;
}
union联合体定义
大小端
小端存储,低地址存低位,高地址存高位;大端存储,低地址存高位,高地址存低位。
union Undemo
{
int num;
char c;
};
int main()
{
union Undemo demo;
demo.num = 10;
if (demo.c == 1)
{
//小端机器
}
printf("%d", demo.c);//输出10
return 0;
}
使用方式
格式:
数据类型 变量名字;
属性:
即变量存储类型,添加在变量名以及变量类型之前,旨在说明该变量的属性,即作用范围,包含cuto、static、register。
auto
在c语言中,局部变量定义的时候编译器会在变量类型前默认添加auto,以此说明定义了一个分配在栈区的局部变量,开发者在定义变量时可省略该关键字,在c11中auto已被废弃。
注意:非C++11的cuto。
//auto int a=0;//全局变量不可使用auto,编译提示有坏的存储类
int main()
{
auto int b=0;
int c=0;//同b的定义
return 0;
}
static
修饰局部变量:
定义静态局部变量,在静态存储区分配内存空间,改变变量的存储方式,控制变量的生命周期和作用域,并且只会初始化一次。
void func1()
{
static int a=0;
printf("%d,a++);//输出12345
}
void func2()
{
int a=0;
printf("%d,a++);//输出11111
}
int main()
{
for(int i=0;i<5;i++)
{
fun1();
}
//i=100;
//编译报错,i在作用域外不可访问
//但i的栈未销毁,内存还在,在其作用域外,i的栈可能被用作它用
for(int i=0;i<5;i++)
{
fun2();
}
return 0;
}
修饰全局变量和函数:
限制其作用域为本文件。
//test1.cpp
statiic int a=0;
int b=0;
void func1()
{
printf("%d",a);
}
static void func2()
{
printf("%d",b);
}
//test2.cpp
extern int a;
extern int b;
int main()
{
printf("%d",a);
//printf("%d",b);//编译出错,提示无法解析的外部符号
fun1();//输出a的值0
//fun2();//同上,编译出错,提示无法解析的外部符号
return 0;
}
register
定义寄存器变量,变量存储于寄存器中,因为数据在寄存器中的读取速度会高于内存,可用于提高程序的执行速度。
注意:变量的值必须是单个寄存器能够接受的值,并且仅仅是发送请求,由编译器判断是否采取将其放弃寄存器。不可以对其取地址&,因为不存在地址。
//register int nmb;//编译报错有坏的存储类
//register 不可定义全局变量
int main()
{
register int num=0;
//int* p = #//CPU当中变量时没有地址
do
{}while(num++!=9999999);
return 0;
}
隐含属性
生命周期:
变量的地址存在的有效时间。
作用域:
对代码进行语法层面的隔离,避免重定义等,一般采取{...}进行定义。
void
//void* 提供一种数据抽象的能力 代表的是一个地址 指向一块未知存储数据类型和大小的内存
//可用于接受任何的指针类型,void*执行的是降级操作
void swap(void* p1,void* p2,size_ size)
{
void *ptemp= malloc(size);
memcpy(ptemp,p1);
memcpy(p1,p2);
memcpy(p2,ptemp);
free(ptemp);
}
void func(void)//void代表无,一般作为返回值和参数
{
//函数体
}
int main()
{
//void a;void 无法定义变量 代表的是空
int n1=1,n2=2;
swap(&n1,&n2,sizeof(int));
return 0;
}