欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C++ 数组内存分配及大小计算

程序员文章站 2022-04-07 12:09:59
...

一、数组的内存分配方式

C++中数组在内存中也有静态分配动态分配的区别。静态数组建立的方式为:A a[],它在栈上分配空间;动态方式是使用new,malloc在堆上分配。

数组要么在静态存储区被创建(如全局数组),要么在栈或堆上被创建。数组名对应着(而不是指向)一块内存,其地址与容量在生命期内保持不变,只有数组的内容可以改变。

C++ 数组内存分配及大小计算

程序中用指针指向了一个常量字符串"world",C++常量字符串存在常量存储区,且不能修改,故会出错。
数组的在栈上分配,或堆上分配的区别可以看下例:将test和main函数修改为下:

C++ 数组内存分配及大小计算

很明显程序程序编译时出现:warning C4172: returning address of local variable or temporary。在test调用结束后在栈上分配的数组已经销毁,p即为野指针指向无效内容。这里把数组名作为l函数返回值。如果换成下面注释的代码在堆上分配则没有问题,注意最后的'\0',字符串的最后是以'\0'来判断结束的,不然会出界输出无效内容。这里可以看出C++数组在内存中的存储形式与上篇内容介绍的一样。将test改为如下:

C++ 数组内存分配及大小计算

静态数组名用sizeof可以知道数组实际所占的内存大小,而指向数组的指针占用空间即为普通指针的大小。当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针

二、数组作为函数参数传递时退化为指针

对字符串进行 sizeof 操作的时候,会把字符串的结束符“\0”计算进去的; sizeof为运算符

进行 strlen操作求字符串的长度的时候,不计算\0 的。 strlen是库函数参数类型是char*,制单遇到“\0”才会结束。

数组作为函数参数传递的时候,已经退化为指针了,Func 函数的参数 a 只是表示一个指针,那个 100 不起任何作用的。改成void Func(char a[2]),输出结果不变。

#include <iostream>
#include <stdio.h>
using namespace std;
void Func(char a[100]) {
    printf("%d\n", sizeof(a));//4
    printf("%d\n", strlen(a));//5
}

int main() {
    char str[] = "Hello";
    printf("%d\n", sizeof(str));//6
    printf("%d\n", strlen(str));//5
    char *p = str;
    printf("%d\n", sizeof(p));  //4
    Func(str);
}

 

输出:6 5 4 4 5

#include <iostream>
#include <stdio.h>
using namespace std;
void Func(char a[100]){
    printf("%d\n",sizeof(a));
    printf("%d\n",strlen(a));
}
int main(){
    char str[100]="Hello";
    printf("%d\n",sizeof(str));//100
    printf("%d\n",strlen(str));
    char *p=str;
    printf("%d\n",sizeof(p));
    Func(str);
}

输出:100 5 4 4 5

 

汇总代码:

void calChar(char * a)
{
	cout <<"calChar:sizeof(a)="<<sizeof(a)<<" strlen(a)="<<strlen(a)<<endl;
	cout <<"calChar: "<< a << endl;
}

int main()
{
	//CPicTest::Instance().printInfo();
	//test();

	char a[11] = "hellohello"; //在栈上       "hellohello"字符串后面默认还有一个 '\0'
	char *b = "hahahahaha";    //在静态存储区 "hellohello"字符串后面默认还有一个 '\0'
	char* c = new char[6];     //在堆上
	c[0] = 'h';
	c[1] = 'e';
	c[2] = 'h';
	c[3] = 'e';
	c[4] = 'h';
	c[5] = '\0'; //如果不添加结束符,输出会乱码

	a[0] = 'H';
	//b[0] = 'H';//编译可以成功,运行会出错
	c[0] = 'H';
	
	cout << a << endl;
	cout << b << endl;
	cout << c << endl;
	cout << sizeof("hahahahaha");


	cout <<"sizeof(a) = "<<sizeof(a)<<" strlen(a) = "<<strlen(a)<<endl;  //输出11 10
	cout <<"sizeof(b) = "<<sizeof(b)<<" strlen(b) = "<<strlen(b)<<endl;  //输出 4 10
	cout <<"sizeof(b) = "<<sizeof(c)<<" strlen(b) = "<<strlen(b)<<endl;  //输出 6 5
	calChar(a); // 输出4 10
	calChar(b); // 输出4 10
	calChar(c); // 输出4 5

如果c[5] = '\0'注释掉,输出为:

C++ 数组内存分配及大小计算

 


在上一篇关于C++中类在内存中分配的介绍举例时发现一个问题,当两个指针指向同一个对象时,发现delete一个指针销毁该对象后,用另一个指针扔能调用该类的函数,这个是野指针应该有错啊。看下面的例子:

C++ 数组内存分配及大小计算

程序运行结果:

C++ 数组内存分配及大小计算

即两次输出class of a,一次是在test函数内,一次是s调用。test内的a分配在栈上,函数结束后应该就销毁了,为什么s还能调用fun。原来类中的成员数据和函数是存放在不同位置的。C++类的方法存放在"程序代码区",而类中的数据成员(对象数据成员)存放在类的实例对象中,即该成员数据存放在堆或栈中。s指向对象的成员数据已销毁,而类的方法还在。

若将上面代码第8行改为:cout<<"class of a:"<<this->num<<endl;程序运行结果为:

C++ 数组内存分配及大小计算

 即s输出的数据成员num为无效,因为该对象已释放。关于C++内存管理还有很多内容,需要进一步加强学习。

 

参考:

https://blog.csdn.net/u011555996/article/details/79496156

https://www.cnblogs.com/seven7seven/p/3659309.html

 

相关标签: C++经典面试题