动态空间申请
静态分配
1、在程序编译或运行过程中,按事先规定大小分配内存空间的分配方式。int a [10];
2、必须事先知道所需空间的大小。
3、分配在栈区或全局变量区,一般以数组的形式
动态分配
1、在程序运行过程中,根据需要大小自由分配所需空间。
2、按需分配。
3、分配在堆区,一般使用特定的关键字进行分配
new和delete
new申请堆区空间 ,delete释放空间
int *p = NULL;
p = new int;//从堆区申请int类型大小的空间
*p = 100;
cout<<"*p="<<*p<<endl;//100
//释放空间
delete p;
//new申请空间的同时 初始化空间内容
int *p1 = NULL;
p1 = new int(100);
cout<<"*p="<<*p<<endl;//100
delete p1;
new和delete操作数组空间
#include<iostream>
using namespace std;
int main()
{
int *p=NULL;
p=new int[5]{1,2,3,4,5};//new与[]结合表示申请数组空间
int i=0;
for (;i<5;i++)
{
cout<<p[i]<<endl;
}
delete [] p;// delete释放的时候也需要[]
return 0;
}
字符串处理函数
以str开头的字符串处理函数 默认遇到’\0’结束操作
#include <string.h> //必要的头文件
测量字符串的长度 strlen
#include <string.h>
size_t strlen(const char *s);
s指 需要测量字符串的首元素地址
char str1[128]="hello";
strlen(str1);//5
char str2[128]="he\0llo";
strlen(str2);//2
字符串拷贝函数 strcpy与strncpy
#include <string.h>
char *strcpy(char *dest, const char *src);
char *strncpy(char *dest, const char *src, size_t n);
dest:目的空间地址
src:原字符串的首元素地址
char dst[128]="";
char src[]="hello\0world";
strcpy(dst,src);
cout<<dst<<endl;//hello
char dst1[]="";//dst1数组只有1字节 当src1拷贝到dst1中 造成溢出(内存污染)
char src1[]="helloworld";
strcpy(dst1, src1);
cout<<dst1<<endl;//hello world(污染内存)
字符串追加函数strcat与strncat
#include <string.h>
char *strcat(char *dest, const char *src);
char *strncat(char *dest, const char *src, size_t n);
将src指向的(前n个字符)字符串 追加到 dest指向的字符串尾部
char dst[128]="hello";
char src[]="world";
strcat(dst,src);
cout<<dst<<endl;//helloworld
char dst[128]="hello";
char src[]="world";
strncat(dst,src,3);
cout<<dst<<endl;//hellowor
字符串比较strcmp
include <string.h>
int strcmp(const char *s1, const char *s2);
int strncmp(const char *s1, const char *s2, size_t n);
返回值:
>0 s1字符串 > s2字符串
<0 s1字符串 < s2字符串
==0 s1字符串==s2字符串
比较的是字符的ascii码值,依次比较,
结构体
将不同类型的数据组合成一个有机的整体
利用struct关键字 可以将不同类型封装在一起,形成新的结构叫做"结构体"
定义结构体
struct 结构体类型名
{
成员列表;
};//注意此处有分号
//定义结构体类型
//系统不会为结构体类型开辟空间 只会为结构体类型定义的变量开辟空间
struct Student
{
int num;//结构体成员,定义结构体类型时 不要给成员初始化值
char name[32];
};
//结构体中的成员拥有独立的空间
//结构体定义变量
Student lulu;//lulu为结构体变量名
Student bob;//bob为结构体变量名
结构体变量的初始化
结构体变量不初始化, 变量中的成员内容不确定(随机值)
结构体变量的初始化 必须遵循成员的顺序以及成员自身的数据类型
struct Student
{
int num;//结构体成员
char name[32];
};
Student lulu={100,"lulu"};
cout<<lulu.num<<" "<<lulu.name<<endl;//100 lulu
memset清空整个结构体变量
void *memset(void *_Dst,int _Val,size_t _Size);
将地址从_Dst开始 长度位_Size的所有字节赋值位_Val
#include<string.h>
struct Stu
{
int num;
char name[32];
};
int main()
{
Stu lulu;
//清空整个结构体变量
memset(&lulu, 0, sizeof(lulu));//未初始化的成员是随机值,使用memset进行赋值0
cout<<lulu.num<<" "<<lulu.name<<endl;
}
给结构体变量中成员赋值
#include<iostream>
#include <string.h>
using namespace std;
struct Stu
{
int num;
char name[32];
};
int main()
{
Stu lulu;
memset(&lulu, 0,sizeof(Stu));
cout<<"请输入学号 姓名:";
cin>>lulu.num>>lulu.name;
cout<<lulu.num<<" "<<lulu.name<<endl;
return 0;
}
单独操作结构体中成员 必须遵循结构体自身的类型
#include<string.h>
struct Stu
{
int num;
char name[32];
};
Stu lulu ={100,"lulu"};
lulu.num += 100;//num是int类型
//name成员时数组名 位符号常量 不允许用=给name赋值,要用字符串替换
//lulu.name = "bob";//err
strcpy(lulu.name, "bob");
相同类型的结构体变量 之间赋值方法
Stu lulu = {100,"lulu"};
Stu bob;
#if 0
//第一种方法:逐个成员赋值(遵循成员类型)
bob.num = lulu.num;
strcpy(bob.name, lulu.name);
#elif 1
//第二种方法:相同类型的结构体变量 可以直接赋值
bob = lulu;
#else
//第三种方式:内存拷贝(是第二种的底层实现)
memcpy(&bob, &lulu, sizeof(Stu));
#endif
cout<<bob.num<<" "<<bob.name<<endl;//100 lulu
结构体嵌套结构体
结构体嵌套结构体 注意访问到最底层
struct Date
{
int year;
int month;
int day;
};
struct Student
{
int num;
char name[32];
Date ob;
};
Student lulu;
cout<<lulu.num<<" "<<lulu.name<<endl;
cout<<lulu.ob.year<<" "<<lulu.ob.month<<" "<<lulu.ob.day<<endl;
结构体数组
结构体数组:本质是数组 只是数组的每个元素位结构体变量
#include<iostream>
#include <string.h>
using namespace std;
struct Stu
{
int num;
char name[32];
};
int main()
{
Stu arr[2]={{100,"lulu"},
{101,"caicai"}};
int n=sizeof(arr)/sizeof(arr[0]);
int i =0;
memset(arr,0,sizeof(arr)); //清空结构体数组
for(i=0;i<n;i++) //给结构体数组赋值
{
cin>>arr[i].num;
cin>>arr[i].name;
}
for(i=0;i<n;i++) //遍历结构体数组
{
cout<<arr[i].num<<"\t"<<arr[i].name<<endl;
}
return 0;
}
结构体指针变量
结构体的指针变量:本质是变量 只是该变量 保存的是结构体变量的地址
#include<iostream>
#include <string.h>
using namespace std;
struct Stu
{
int num;
char name[32];
};
int main()
{
Stu caicai={100,"caicai"};
Stu* p=&caicai;
cout<<(*p).name<<endl; //结构体变量用.指针成员
cout<<p->name<<endl;
cout<<(&caicai)->name<<endl; //结构体指针变量(地址)用->指针成员
return 0;
}
结构体数组元素的指针变量
指针变量 保存结构体数组 元素的地址
#include<iostream>
#include <string.h>
using namespace std;
struct Stu
{
int num;
char name[32];
};
void InputArr(Stu*arr,int n)
{
int i=0;
for(i=0;i<n;i++)
{
cin>>arr[i].num;
cin>>arr[i].name;
}
}
void SortArr(Stu*arr,int n)
{
int i=0,j=0;
Stu tem;
for(i=0;i<n;i++)
{
for(j=0;j<n-1;j++)
{
if(arr[j].num>arr[j+1].num)
{
tem=arr[j];
arr[j]=arr[j+1];
arr[j+1]=tem;
}
}
}
}
void OutputArr(Stu*arr,int n)
{
int i=0;
for(i=0;i<n;i++)
{
cout<<arr[i].num<<"\t"<<arr[i].name<<endl;
}
}
int main()
{
Stu arr[3];
int n=sizeof(arr)/sizeof(arr[0]);
memset(arr,0,sizeof(arr));
InputArr(arr,n); //键盘输入结构体数组
SortArr(arr,n); //排序
OutputArr(arr,n); //输出
return 0;
}
结构体的指针成员
struct Stu
{
int num;
char *name;
};
Stu lulu = {100, "hello world"};
lulu.name保存的时"hello world"的首元素地址, 而"hello world"字符串本身存储在文字常量区
struct Stu
{
int num;
char *name;
};
Stu lulu;
lulu.num = 100;
lulu.name = new char[32]; //利用new在堆区中开辟空间
strcpy(lulu.name, "hello world"); //此时hello world保存在堆区中
cout<<lulu.num<<" "<<lulu.name<<endl;
delete [] lulu.name;
结构体的浅拷贝
相同类型的结构体变量可以整体赋值,默认赋值方式为:浅拷贝
浅拷贝:将结构体变量空间内容 赋值一份 到另一个相同类型的结构体变量空间中
如果结构体中没有指针成员 浅拷贝 不会带来问题。
如果结构体中有指针成员 浅拷贝 会带来多次释放堆区空间的问题。
struct Stu
{
int num;
char *name;
};
Stu lulu;
lulu.num = 100;
lulu.name = new char[32]; //利用new在堆区中开辟空间
strcpy(lulu.name, "hello world");
Stu caicai;
caicai=lulu;
delete [] lulu.name; //lulu.name与caicai.name,指向的是同一个堆区空间
delete [] caicai.name;
结构体的深拷贝
如果结构体中有指针成员 尽量使用深拷贝
所谓的深拷贝,就是为结构体的指针成员 分配独立空间 然后再内容拷贝
Stu lulu;
lulu.num = 100;
lulu.name = new char[32];
strcpy(lulu.name, "hello world");
Stu caicai;
caicai.num = lulu.num;
caicai.name = new char[32];
strcpy(caicai.name,lulu.name);
cout<<caicai.num<<" "<<caicai.name<<endl;
delete [] lulu.name;
delete [] caicai.name;
结构体变量在堆区 结构体的指针成员也指向堆区
struct Stu
{
int num;
char *name;
};
Stu *p = new Stu; //在堆区申请一个结构体空间
p->name = new char[32];//结构体中指针成员指向堆区
p->num = 100; //成员num在堆区
strcpy(p->name, "hello world"); // 成员name也在堆区
cout<<p->num<<" "<<p->name<<endl;
delete [] p->name;//先释放结构体成员空间
delete p;//再释放结构体空间
结构体的对齐规则
char 1 字节
short 2字节
int long float 4字节
double 8字节
自动对齐规则
1、确定分配单位(一行分配多少字节)
结构体中最大的基本类型 长度决定。
2、确定成员的偏移量
成员偏移量 = 成员自身类型的整数倍。
3、收尾工作
结构体的总大小 = 分配单位整数倍
当结构体成员中出现数组的时候,可以看成多个变量。
成员偏移量 = 成员自身类型的整数倍。
short 2字节,起始内存编号是2的倍数
int long float 4字节,起始内存编号是4的倍数
double 8字节,起始内存编号是8的倍数
struct stu{
char a;
short b;
int c;
}temp; //8个字节
struct stu{
char a;
int c;
short b;
}temp; //12个字节
强制对齐规则
#pragma pack (value)时的指定对齐值value。
注意value值为1 2 4 8 16
指定对齐值与数据类型对齐值相比取较小值
1、确定分配单位(一行分配多少字节)
分配单位 = min(结构体中最大的基本类型, value)
2、确定成员的偏移量
成员偏移量 = 成员自身类型的整数倍。
3、收尾工作
结构体的总大小 = 分配单位整数倍
#pragma pack(2)
struct stu{
char a;
int b;
} ;//默认占8个字节,value设定为2,则占6个字节,设定为1,则占5个字节
位段
在结构体中,以位为单位的成员,称之为位段(位域)。
struct stu{
unsigned int a:2; //定义a占2位
unsigned int b:6;//定义b占6位
unsigned int c:4;//定义c占4位
unsigned int d:4;//定义d占4位
unsigned int i;
} data; //总sizeof占8字节,2+6+4+4=16位,两字节+(两字节)+四字节=8字节
不能对位段成员取地址,位段成员可能不够1字节
对位域赋值 不要操作 位域本身位的宽度
data.a =2//a的取值范围是00–11,转十进制是0–3
赋值时,不要超出位段定义的范围;如段成员a定义为2位,最大值为3,即(11)2,所以data.a =5,就会取5(101)的低两位进行赋值01
位段的长度不能大于存储单元的长度
char a:9;//char 1个字节最多8位,
另起一个储存单元
unsigned char b:2;
unsigned char :0;//作用是使下一个位段从,下一个存储单元开始存放
unsigned char c:3;(另一个单元)
无意义位段
unsigned a: 1;
unsigned : 2;//可以定义无意义位段
unsigned b: 3;
共用体union
结构体:所有成员拥有独立空间
共用体:所有成员共享同一块空间
共用体关键字:union
共用体的空间 是由最大的成员类型决定
成员共享同一块空间,但是每个成员 能操作的空间的范围 是由成员自身类型长度决定。
union Data
{
char a;
short b;
int c;
};
Data ob;
ob.c = 0x01020304; //ob.c:01020304 ob:b:0304 ob.a =04
ob.b = 0x0102; //ob.c:01020102 ob:b:0102 ob.a =02
ob.a = 0x01; //ob.c:01020101 ob:b:0101 ob.a =01
cout<<ob.a+ob.b+ob.c<<endl;//0x01020203
枚举 enum
枚举:将枚举变量 要赋的值 一一列举出来
enum 枚举类型名{
枚举值列表(枚举元素);
};
枚举值是常量,不能在程序中用赋值语句再对它赋值
枚举元素本身由系统定义了一个表示序号的数值,默认是从0开始顺序定义为0,1,2…
可以改变枚举值的默认值
enum week
{
mon,tue,wed,thu,fri,sat,sun //0,1,2,3,4,5,6,7
};
enum week
{
mon=2,tue,wed,thu,fri=1,sat,sun //2,3,4,5,1,2,3改变枚举值的默认值
};