(1)内存在逻辑上就是一个一个的格子,这些格子可以用来装东西,也就是内存中的数据,每个格子都有一个固定的编号,这个编号0、1、2、3就是内存地址,这个内存地址(一个数字)和这个格子的空间是一一对应的并且是永久绑定的。
(2)cpu在内存或硬盘里面寻找一个数据时,先通过地址线找到地址,然后再通过数据线将数据取出来。
(3)在程序运行时,CPU只认识内存地址,而不关心这个地址所代表的空间在哪里以及分布,因为硬件的设计保证了只要有地址,就一定能找到这个盒子在哪里,所以内存单元有两个概念:地址和空间。
(4)内存编址是以字节为单位,每一个内存地址对应的内存大小的空间是固定的,就是一个字节。
32位/64位系统----32根/64根地址线----物理线用通电来记录----用1/0来编写地址线
32位系统支持ram最大为2^32type即4GB
64位系统支持ram最大为2^64type即128GB
先用高地址空间,再用低地址空间。
数组与变量之间的内存占据情况:
vs 6.0h环境下——空0个整型
gcc环境下——空一个整型
VS2013——VS2019——空1或2个整型
注:相较于函数中的传值调用,传址调用更为优势,可以减少创建局部变量所开辟内存的使用,从而减少内存的占用。
执行同一个程序每次输出的变量地址不一样(地址空间随机化分布,相当于重新开辟一个空间)
#include
void main()
{
int a = 13;
printf("%p\n", &a);
}
“&p”,&变量专门用来打印地址
创建并格式化指针变量:数据类型* +名称 = &+对应变量的名称
例如:
int a = 10;
char ch = 'h';
int* p1 = &a;
//创建指针变量p1来储存a的地址
char* p2 = &ch;
//创建指针变量p2来储存ch的地址
#include
void main()
{
int a = 13;
int* pa = &a;
*pa = 20;
//* 解引用操作
//*pa通过pa里面的地址来找a
printf("%d %d", a,*pa);
}
32位下指针变量为4字节
64位下指针变量为8字节
指针大小与地址线数量有关,而地址线与系统位数相关
int arr[5] = {0};
arr = &arr[0];
//arr数组名称的指针储存的是数组的首元素的地址
&arr
//&arr取出的是整个数组的地址
&arr与&arr+1相差20字节
arr与arr+1相差4字节
注:在函数中传入的数组为数组首位的指针,故在函数中利用sizeof计算的结果为指针变量的内存大小。
理解:指针的类型决定指针向前或后走一步的距离
void main()
{
int arr[] = { 0 };
int* p = arr;
char* cp = arr;
printf("%p\n", p);
printf("%p\n", p + 1);
printf("%p\n", cp);
printf("%p\n", cp + 1);
}
//输出结果第一行地址与第二行地址相差4
//输出结果第三行地址与第四行地址相差1
example:
void main()
{
int arr[] = {1,2,3,4,5};
short* p = (short*) arr;
for (int i = 0; i < 4; ++i)
{
*(p + i) = 0;
}
//由于p是short类型的指针变量,所以移动单位为2字节
for (int i = 0; i < 5; ++i)
{
printf("%d ", *(arr + i));
}
}
//输出结果为0 0 3 4 5
void*
可以接受任何类型的指针
(3条消息) 类qsort的多用冒泡排序函数_HS-Cai的博客-CSDN博客https://blog.csdn.net/qq947467490/article/details/128068613
1.对指针初始化
2.避免指针越界
3.指针指向空间释放即使置NULL
int* p = NULL;
//当不知道p该初始化什么地址的时候,直接初始化为NULL
void test2(int** arr2)
{}
void main()
{
int* arr2[10] = { 0 };
test2(arr2);
}
指针数组的名称为首元素的指针的地址
#include
//单独声明结构标记
struct BOOK
{
char name[20];
//创建成员变量
int page;
float price;
};
void main()
{
struct BOOK s = { "Rich Dad Poor Dad",351,48.00 };
//创建并初始化结构体变量s
printf("%s %d %.2f$", s.name, s.page, s.price);
//对结构体变量s中的成员变量进行打印
}
如果加上指针的运用可以写成
#include
struct BOOK
{
char name[20];
int page;
float price;
};
void main()
{
struct BOOK s = { "Rich Dad Poor Dad",351,48.00 };
struct BOOK* p = &s;
//此处应注意数据类型,来创建指针变量
printf("%s %d %.2f$", p->name, p->page, p->price);
}
如果先创建结构体变量后格式化可以写成
#include
struct BOOK
{
char* name;
int page;
float price;
};
void main()
{
struct BOOK s1;
s1.name = "RICH";
s1.page = 111;
s1.price = 15.80;
printf("%s\n%d\n%.2f$", s1.name, s1.page, s1.price);
}
[重点]注:如此定义结构体必须要使用指针来创建字符串
#include
struct BOOK
{
char name[20];
int page;
float price;
}s1 = { "Rich Dad Poor Dad",351,48.00 }, s2;
//同时声明了结构体变量s1,s2
//此时s1,s2为全局变量
void main()
{
printf("%s\n%d\n%.2f$", s1.name, s1.page, s1.price);
}
#include
//利用typefed函数将struct BOOK重定义为book
typedef struct BOOK
{
char name[20];
int page;
float price;
}book;
void main()
{
book s1 = { "Rich Dad Poor Dad",351,48.00 };
printf("%s\n%d\n%.2f$", s1.name, s1.page, s1.price);
}
//嵌套结构体的使用
#include
struct publication
{
int year;
int month;
int day;
};
struct BOOK
{
struct publication c;
char name[20];
int page;
float price;
};
void main()
{
struct BOOK s1 = { {1997,11,14} , "Rich Dad Poor Dad" , 351 , 48.00 };
printf("%d.%d.%d\n%s\n%d\n%.2f$", s1.c.year, s1.c.month, s1.c.day, s1.name, s1.page, s1.price);
}
注:嵌套使用另一个结构体需要,在主结构体中创建所嵌套使用的结构体变量。
#include
struct book
{
char* name;
int page;
float price;
};
void print(struct book* p)
{
printf("%s", p->name);
}
void main()
{
struct book s[3] = { {"POOR", 168, 28.00} ,{"RICH", 172, 25.00} ,{"WINNER", 180, 24.00} };
print(s + 1);
}
函数传参的时候,参数是需要压栈的。如果传递—个结构体对象的时候,结构体过大,参数压栈的时候系统开销会比较大,所以会导致性能的下降。
结论:结构体传参的时候,要传结构体的地址。
example:
将结构体变量b的地址传给函数print
#include
struct publication
{
int year;
int month;
int day;
};
struct BOOK
{
struct publication s2;
char* id;
int page;
float price;
};
void print(struct BOOK* b)
{
printf("%d.%d.%d\n%s\n%d\n%.2f\n", b->s2.year, b->s2.month, b->s2.day, b->id, b->page, b->price);
}
void main()
{
struct BOOK b = { {1997,11,14},"POOR OR RICH",197,25.00 };
print(&b);
}
1、找到结构体中最大的成员变量所占的字节数
2、结构体中成员变量的起始地址为该成员变量大小的整数倍(一般情况下我们认为第一个成员变量的起始地址为0)
3、结构体变量的总大小必须要是结构体中最大变量字节的整数倍(不足补齐)
example:
struct demo{
short a;
double b;
int c;
}demo;
a从0开始占2个字节,因为b为8个字节所以起始地址必须从8开始到16,c变量起始地址从16开始到20,总共20个字节,但是因为结构体变量的总大小必须为8字节的倍数,所以补齐为24