c++基础动态内存结构体字符串

动态空间申请

静态分配

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改变枚举值的默认值
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值