sizeof
- sizeof 返回的是变量(单个变量或结构体)实际所占用的空间的大小
typedef struct Person
{
char a;
int b;
}PERSON;
int main()
{
std::cout << "Hello World!\n";
printf("int size is %d\n", sizeof(int));
double a = 3.14;
printf("a size is %d\n",sizeof(double));
PERSON xiaoming;
printf("xiaoming size is %d\n",sizeof(xiaoming));
}
输出结果:
Hello World!
int size is 4
a size is 8
xiaoming size is 8
- 对齐模式问题
#pragma pack(1)
typedef struct Person
{
char a;
int b;
}PERSON;
int main()
{
PERSON xiaoming;
printf("xiaoming size is %d\n",sizeof(xiaoming));
}
输出结果:
xiaoming size is 5
- sizeof 返回的类型是unsigned int类型
void test(void)
{
unsigned int a = 10;
if (a - 20 > 0)
{
printf("大于0\n");
}
else
{
printf("小于0\n");
}
}
输出结果是“大于0”, 因为sizeof()的返回值是unsigned int类型。
- sizeof 计算数组,数组作为函数参数会退化为指向数组首元素的指针
int caculateArraySize(int arry[]) //传数组时写这种方式比较好
{
return sizeof(arry);
}
void test1()
{
int arr[] = {1,2,3,4,5,6};
printf("arr size is %d\n",sizeof(arr));
printf("sizeof arry is %d\n", caculateArraySize(arr));
}
输出结果:
arr size is 24
sizeof arry is 4
变量的间接赋值
void test01()
{
//直接赋值
int a = 10;
a = 100;
//间接赋值
int *p = &a;
*p = 200;
}
typedef struct Person
{
char a;
int b;
char c;
int d;
}PERSON;
void test02()
{
PERSON p = {'a',100,'b',200};
printf("p.d: %d\n",p.d);
p.d = 2000;
printf("%d\n",(char*)&p+12); //输出d的地址
printf("%d\n",&(p.d)); //输出d的地址
printf("%d\n",*(int *)((char *)&p + 12)); //输出d的值
//&p
int *pp=NULL;
printf("pp:%d\n",pp);
printf("pp+1:%d\n", pp+1);
}
输出结果
p.d: 200
7338780
7338780
2000
pp:0
pp+1:4
内存分区概念
运行之前
- 预处理:宏定义展开,头文件展开,条件编译,这里并不检查语法
- 编译: 检查语法,并将预处理后文件编程生成汇编文件
- 汇编:将汇编文件生成目标文件(二进制文件)
- 链接:将目标文件链接为可执行程序
在没有运行程序前,也就是说程序没有加载到内存前,可执行程序内部已经分好3段信息,分别为代码区(text),数据区(data), 未初始化数据区(bss)
栈变量和堆变量在运行时才有
- 代码区 共享(避免内存浪费),只读
运行之后
额外增加栈区,堆区
- 堆区 heap:自己控制申请和释放。程序泄漏问题。一般数据量较大时放堆上。
- 栈区 stack:编译器自动申请和释放。一般栈大小固定。
全局静态区
全局静态区包含: 全局区,静态区,常量区
extern int a; //外部链接属性
static int a; //作用域在本文件内
常量区存放什么?
const char *p = "Hello World",//字符串常量前最好加上const
const 修饰的全局变量
常量区的数据,一旦初始化,不能修改,只读内存。
栈区
不要返回局部变量的地址
int* myFun()
{
//不要返回局部变量的地址,退出时,a的内存已经被回收
int a=10;
return &a;
}
void test()
{
int *p = myFun();
printf("*p=%d\n", *p); //虽然输出结果是*p = 10,但是 之前变量a占用的内存可能被其他变量占用
}
char* getString()
{
char str[] = "Hello world"; //数组在栈上
return str;
}
void test2()
{
char *s = NULL;
s = getString();
printf("s = %s\n",s);
}

堆区
int *getSpace()
{
int *p = (int *)malloc(sizeof(int) * 5);
if (NULL == p) //NULL放前面习惯,因为当只有一个等号时会报错
{
return NULL;
}
//主要是连续内存空间,都能使用下标的方式方位内存
for (int i=0;i<5;++i) //前置++效率比较高,
{
p[i] = 100 + i;
}
//退出时在栈上的p会释放掉,但是堆上的分配的内存还在
return p;
}
void test3()
{
int *ret = getSpace();
for (int i=0;i<5;i++)
{
printf("%d \n", ret[i]);
}
free(ret);
ret = NULL; //释放完后最好置成空
}
void allocateSpace(char *p)
{
p = (char*)malloc(100);
memset(p,0,100);
strcpy(p,"hello world");
}
void test04()
{
char *p = NULL;
allocateSpace(p); //函数的形参也是个局部变量,函数返回时也要释放
printf("p=%s\n",p);
}

void allocateSpace2(char **p)//为什么要写两个*,便于区分指向的数据是什么数据
{
char *tmp = (char*)malloc(100);
memset(tmp, 0, 100);
strcpy(tmp, "hello world");
*p = tmp;
}
void test05()
{
char *p = NULL;
allocateSpace2(&p);
printf("p=%s\n", p);
}

void fun(char **p) //对指针取地址,升一个*,变成两个**
{
...;
*p = xx;
}
test()
{
char *p =NULL;
fun(&p);
}


全局区、静态区
//extern int a = 10; 默认外部链接
int a= 10; //全局区
//静态全部变量时内部链接
static int b = 20; //静态区
//内部链接和外部链接有什么区别:
//1.static 只能在当前文件内访问
//2.外部链接,此变量可被外部访问
//1.全局静态变量和局部静态变量都存储在静态区,在程序运行期间都是合法有效
//2.局部静态变量符号的可见范围仅限于当前函数内部,全局静态变量可见范围从定义到文件结尾
//3.头文件不参与编译,每一个.c文件,叫做一个编译单元
//4.编译器独立编译每个.c文件
void test01()
{
static int c = 30;
}
常量区、字符串常量、全局const变量
- const全局和局部变量区别?
- const全局变量在常量区,不能修改(直接或间接)
const int g_c = 100;
//&g_c 的类型为const int*类型
int *p = &g_c; //此时编译器会报warning, 不同类型的两个指针赋值,就会报错
//解决方法:
int *p = (int *)&g_c; //强转
*p = 200; //此时编译器会报错,全局const放在常量区,一旦初始化,不能修改
- const局部变量
void test()
{
//栈上
const int a = 100;
//a=200; //编译器报错
int *p = (int *)&a; //跳过编译器的检查了,运行时把a的值修改了
*p = 200;
printf("a=%d\n",a); //a的值被修改
}
字符串常量区
void test()
{
char *p = "Hello World";
printf("%d\n",&"Hello World");
printf("%d\n",p);
//两者输出的地址是一样的
}
- ANSI C中规定:修改字符串常量,结果是未定义的
- ANSI C并没有规定编译器的实现者对字符串的处理,例如:
1.有些编译器可以修改字符串常量,有些编译器不可修改
2.有些编译器把多个相同的字符串常量看成一个,有些进行优化(节省空间),有些则不进行优化。
void test()
{
char *p1 = "Hello world";
char *p2 = "Hello world";
printf("%d\n",p1);
printf("%d\n",p2);
//两者输出根据编译器而不同
}
3.所以尽量不要去修改字符串常量!
本文深入探讨C++中的sizeof运算符用法,数组、指针与内存管理技巧,包括堆栈变量的区别,内存对齐及内存分区概念。通过实例讲解如何正确使用指针,避免常见错误,如返回局部变量地址和修改字符串常量。
1123

被折叠的 条评论
为什么被折叠?



