一,基础数据类型
short,int,long,long long 都对应unsigned 标记用来表示无符号,全数据位!
char类型本质存储的是对应字符的ASCLL码(数字)!
跨平台注意不要使用long类型:windows平台和其它平台对long的字节数支持不一致!
指针类型:所占字节数取决于机器的位数(32/64)!
二,复杂数据类型
2.1-数组篇
数组就是一个用来存储多个相同数据类型的一个集合,内存分布:占据连续的一段内存空间!
声明:
数据类型 数组名[数组长度] = {初始化};
数据类型:
用来说明数组中每个元素的数据类型,站在编译器的角度就是每个元素所占的内存空间大小!
数组长度:
用来表明数组中元素的个数!
内存计算:
数据类型(字节) 数组长度 = 数组内存空间大小!
数组名:
用来标识我们所开辟的内存空间的或者说用来标识我们的数组的,指向数组中第一个元素的常指针!
初始化:
在创建数组的同时,就初始化数据,如果未初始化则以数据类型默认数据填充初始化!
遍历:
下标访问:
数组名[下标] //数组中的元素是从0开始编号的,元素下标 = 元素位置 -1
指针访问:
int ary[5] = {1,2,3,4,5};
int pAry = ary;
int iFirstNum = pAry;//获取第一个元素
iFirstNum = pAry[0];//支持下标访问元素
获取个数:
int iAryCount = sizeof(ary)/sizeof(int);
数组遍历:
*1)下标遍历
int ary[] = {8,7,6,5,4,3,2,1};
int aryCount = sizeof(ary)/sizeof(int);
for(int i = 0;i < aryCount;i++)
{
printf("index=%d,value=%d\n",i,ary[i]);
}
2)指针遍历
int ary[] = {8,7,6,5,4,3,2,1};
int* pAry = ary;
int aryCount = sizeof(ary)/sizeof(int);
for(int i = 0;i < aryCount;i++){
//i=0 -> i=count -1
//printf("index=%d,value=%d\n",i,pAry[i]);
printf("index=%d,value=%d\n",i,*pAry++);
}
pAry = ary;
二维:
矩阵式数组,也就是说是具有行和列的数组,你也可以理解为数组中的每个元素又是一个数组,大桶里套个桶!
声明:
数据类型 数组名[行数][列数];
遍历:
int ary[2][3] = {{1,2,3},{4,5,6}};
for(int i = 0;i<2;i++)
{
printf("row index=%d ",i);
for(int j = 0;j<3;j++)
{
printf(" %d ",ary[i][j]);
}
printf("\n");
}
2.2-字符串
由一个一个字符所构成的串,用双引号进行标识,存储在文字常量区,有效字符+结束符!
数组存储:
char str[] = "hello";//h e l l o 0 尾部结束符(零)
int strCount = sizeof(str);//6 有效字符 + 结束符
2.3-结构体
结构体就是用来存储多个相同或者不同数据类型元素的集合!
声明:
//仅声明 定义:struct Student stu;
struct Student
{
};
//声明 && 定义
struct Teacher
{
}teacher;
//声明(匿名结构类型) && 定义
struct
{
}s1;
//声明结构 同时 typedef类型起别名 定义:Class cls;
typedef struct Class
{
}Class;
访问:
结构体变量:结构体变量名.成员名
结构体指针:结构体指针名->成员名
你真的了解结构体?
- C struct
在C语言中,struct不能使用面向对象中的继承,访问控制权限,不可内部定义函数,只能内部定义成员数据,仅用来构建数据结构!
- C++ struct
using namespace std;
struct MyStruct { int num; };
class MyClass { int num; };
int main(int argc, char* argv[]) { MyStruct ms; ms.num = 100;//可访问 默认public
MyClass mc;
mc.num = 100;//不可访问 默认private
system("pause");
return 0;
}
- **struct允许定义成员函数(构造函数,析构函数)**
```cpp
#include <stdlib.h>
#include <iostream>
using namespace std;
//struct MyStruct
//{
// int num;
//};
//
//class MyClass
//{
// int num;
//};
struct MyStruct
{
int num;
void PrintNum()
{
printf("num=%d\n", num);
}
MyStruct()
{
num = 999;
printf("MyStruct 构造函数!\n");
}
~MyStruct()
{
printf("MyStruct 析构函数!\n");
}
};
void Test()
{
MyStruct ms;
ms.PrintNum();
}
int main(int argc, char* argv[])
{
//MyStruct ms;
//ms.num = 100;
//MyClass mc;
//mc.num = 100;
Test();
system("pause");
return 0;
}
- **struct允许继承特性(class可以继承struct,struct也可以继承class)**
#include <stdlib.h>
#include <iostream>
using namespace std;
/*struct 继承 class*/
class MyClass
{
public:
int iNumPerson1;
protected:
int iNumPerson2;
private:
int iNumPerson3;
};
//默认继承权限:public继承(父类成员是什么权限还是什么权限)
struct MyStruct : MyClass
{
MyStruct()
{
printf("MyStruct 构造函数!\n");
iNumPerson1 = 100;
iNumPerson2 = 200;
cout << "iNumPerson1 =" << iNumPerson1 << " iNumPerson2 =" << iNumPerson2 << endl;
/*iNumPerson3 = 300;*/
}
~MyStruct()
{
printf("MyStruct 析构函数!\n");
}
};
struct MyStructChild : MyStruct
{
MyStructChild()
{
printf("MyStructChild 构造函数!\n");
iNumPerson1 = 100;
iNumPerson2 = 200;
/*iNumPerson3 = 300;*/
cout << "iNumPerson1 =" << iNumPerson1 << " iNumPerson2 =" << iNumPerson2 << endl;
}
~MyStructChild()
{
printf("MyStructChild 析构函数!\n");
}
};
/*class 继承 struct*/
struct MyStruct2
{
public:
int iNumPerson1;
protected:
int iNumPerson2;
private:
int iNumPerson3;
};
//默认继承权限:private 会导致父类成员全部编程private,导致后续子类也无法访问
class MyClass2 : MyStruct2
{
public:
MyClass2()
{
printf("MyClass2 构造函数!\n");
iNumPerson1 = 100;
iNumPerson2 = 200;
cout << "iNumPerson1 =" << iNumPerson1 << " iNumPerson2 =" << iNumPerson2 << endl;
/*iNumPerson3 = 300;*/
}
~MyClass2()
{
printf("MyClass2 析构函数!\n");
}
};
class MyClass22 : MyClass2
{
MyClass22()
{
printf("MyClass22 构造函数!\n");
//iNumPerson1 = 100;
//iNumPerson2 = 200;
//iNumPerson3 = 300;
//cout << "iNumPerson1 =" << iNumPerson1 << " iNumPerson2 =" << iNumPerson2 << endl;
}
~MyClass22()
{
printf("MyClass22 析构函数!\n");
}
};
void Test()
{
MyStruct ms;
MyClass2 mc2;
}
int main(int argc, char* argv[])
{
Test();
system("pause");
return 0;
}
- **struct支持多态特性**
#include <stdlib.h>
#include <iostream>
using namespace std;
struct Person
{
virtual void Print()
{
printf("Person printf!\n");
}
};
struct Child : Person
{
void Print()
{
printf("Child printf!\n");
}
};
void Test()
{
Child ch;
ch.Print();
}
int main(int argc, char* argv[])
{
Test();
system("pause");
return 0;
}
2.4-共用体
多个数据类型的变量共用一段内存空间,内存空间为数据类型所占内存空间最大的那一个,某一时刻只有一种数据类型起作用!
声明:
union DemoUnion
{
int i1;
long l2;
}demo;
注意:
公用体不可以单独使用,必须配合具体的成员来进行使用
共用体在某个一时刻只可以为其中一种成员数据类型
共用体成员地址相同,共用体对齐为占据最大内存空间成员大小
不能直接引用共用体变量,只能具体到引用共用体具体的成员变量
2.5-枚举篇
固定选项的一种数据类型,本质也是int类型数据!
声明:
enum EM {HAHA,LALA};
2.6-引用篇
引用就好比是一个外号(别名),你给谁起的外号,你通过这个外号找到的就是谁!
声明:
数据类型 &别名 = 关联的对象;
特点:
定义引用就相当于起别名
定义引用必须进行初始化
引用名访问的是所关联对象
本质:
必须初始化(const),占4个字节内存空间(32位) -> 常指针
应用:
作为函数参数:直接关联和访问外部绑定变量!
作为函数返回:直接关联内部局部变量,如果赋值操作无影响,如果外部接收是引用,相当于关联了函数内部的局部变量,当函数执行完毕的时候,变量就会被释放掉,此时使用外部引用就会访问异常内存数据!
2.7-指针篇
指针就是地址,用来找到地址所指向的内存空间的,通过&符号获取对应变量的指针,指针变量本质是个变量,只不过存储的是指针(地址)数据!
声明:
针对指针变量来说,指针变量所存储的指针(地址)所占的空间大小是固定的已知的,站在编译器的角度来看,我们是知道给指针变量开辟多大的内存空间的,那为什么还要有数据类型?我们知道我们通过指针变量名可以获取到一个地址,通过这个地址又可以获取到地址所指向的内存空间,但是我们知道这个内存空间所占的空间大小吗?很显然是不知道的,所以我们也没有办法获取这个内存空间的数据,所以我们必须要知道我们指针变量所直接指向的指针所指向的内存空间的数据类型,也就是空间大小;将谁的地址赋值给指针变量,我们的指针变量就直接指向了这个地址,间接的指向了地址所指向的内存空间!
使用:
指针变量名 -> 指针变量所直接存储的地址
*指针变量名 -> 指针变量所存储指针所指向的内存空间!
类型:
一级指针 * //指针变量->地址->地址对应的内存空间!
二级指针 //指针变量->一级指针变量的地址->地址->地址对应的内存空间;二级指针变量直接指向的是一级指针变量的地址,间接指向的仍然是个指针变量,这个指针变量又直接指向一个地址,间接又指向了这个地址所指向的内存空间
指针数组:指的是一个存储指针的数组,也就意味着这个数组中的每个元素都是一个指针也就是地址!
数组指针:指向一个数组的指针!
结构指针:指向结构体的指针!
内部套指针:结构体中嵌套了一级指针,我们在使用结构体套指针的时候,我们一定要对结构体中的指针进行初始化!
万能指针:void*
它可以用来存储任何类型的指针,平常类型的指针只能存放同类型指针;无类型指针,可以存储任何类型的地址,但是取的时候,必须显示转换!
三,注意事项
int a[4][3] sizeof(a)
无论数组写的有多么复杂总之数组所占内存空间大小:
元素个数(43) 元素类型(指针) = 434 = 48(32位),438 = 96(64位)
int a[5] = {0};
int p = a; p++;//指向第二个元素
int p = a + 1;//a + 1 a是数组,此时+1,跨度:整个数组所占字节数 ,p指向最后一个元素的后一个位置
//指针运算特性:在做指针运算时,一定要清楚当前指针的类型! **
产生字符串崩溃原因:
内存越界崩溃,内存不足strcpy!
字符串不可修改,修改字符串中某个字符!
结构体内存对齐:
结构体对齐计算方式
指针和引用区别:
指针变量是一个指向地址的变量,可以不进行初始化,未来防止野指针,我们必须进行NULL初始化,而引用必须进行初始化,指针变量可以有多级指向,而引用只有一级指向,引用内部封装的更像是常指针,通过引用和变量的绑定, 如果引用直接获取到的就是所关联的变量!
出现野指针的几种情况:
声明指针变量时未进行初始化,那么此时我们的指针变量所存储的地址就是一个无效地址空间!
指针变量指向了一个对象,但是我们的对象被释放或者析构掉了但是这时我们却没有将指针变量置空,那么这时我们的指针变量所指向的这个地址所指向的内存空间就是无效的,那么这时我们的指针变量所存储的就变成了一个野指针!
指针变量所间接指向的这个变量生命周期结束,但是我们的指针变量仍然指向这个地址,那么这时指向的依然是一个野指针!