深刻研究String str = new String("res"); 和 String str = "res";的区别

本文深入探讨了Java中String对象的两种创建方式:直接赋值与new关键字。详细解析了字符串常量池的使用及堆内存中对象的创建过程,帮助理解Java内存管理。

预备知识:

        1. new对象的过程;

        2. 堆和常量池;

1》, 先说 String str = "res"的创建过程 ;

        (过程: 加载类  -- > 初始化类 --> 创建对象  )

        创建一个对象str,将str指向常量池中的res

 

2》,String str = new String("res"); 

#include<iostream> using namespace std; class String { char* str; int len; public: String(char*n=nullptr):str(nullptr),len(0) { if(n){ str = new char[strlen(n) + 1]; strcpy(str, n); } len = strlen(str); } String(String& n) { if (n.str) { str = new char[strlen(n.str) +1]; strcpy(str, n.str); len = n.len; } else { str = nullptr; len = 0; } } ~String() { delete[]str; } void set(char* n) { if (n) { str = new char[strlen(n) + 1]; strcpy(str, n); len = strlen(n); } else { str = nullptr; len = 0; } } void show() { cout << *str<<endl; } int getlen() { return len; } void delchar(char n) { int b = 0; char* m = new char[getlen() + 1]; for (int a = 0;a < getlen();a++) { if (str[a] != n) { m[b] = str[a]; b++; } } m[b] = '\0'; delete[]str; str = new char[strlen(m) + 1]; strcpy(str, m); len = strlen(m); delete[]m; } String &operator-(char n) { delchar(n); return *this; } String& operator=(String& n) { if (n.str) { delete[]str; str = new char[n.getlen() + 1]; strcpy(str,n.str); len = n.len; } else { str = nullptr; len = 0; } return*this; } String& operator+=(String& n) { if (n.str&&str) { String m; m.str = new char[len + n.len + 1]; int a = 0; for (;a < len;a++) { m.str[a] = str[a]; } for (int b=0;a < len + n.len;a++,b++) { m.str[a] = n.str[b]; } delete[]str; str = new char[strlen(m.str) + 1]; strcpy(str, m.str); } return*this; } bool operator==( String& n) { if (strcmp(str, n.str)) { return false; } else { return true; } } friend String operator+(String&,String&); }; String operator+(String&n, String&m) { String res; res.str = new char[n.len + m.len + 1]; int a = 0; for (;a < n.len;a++) { res.str[a] =n. str[a]; } for (int b = 0;a < m.len + n.len;a++, b++) { res.str[a] = m.str[b]; } res.len = strlen(res.str); return res; }
03-24
<think>我们正在讨论C语言中将char指针指向字符数组时的内存分配问题。 用户的问题:将char指针指向一个字符数组时,是否会自动分配内存? 注意:这里的关键词是“字符数组”(char array)“指针”(pointer)。我们需要区分两种情况: 1. 指针指向一个已经存在的字符数组(栈上或堆上)。 2. 指针指向一个字符串字面量(静态存储区)。 回顾上一次的回答:我们明确字符串字面量赋值给指针不会分配动态内存,而是指向静态存储区。 现在,用户的问题是关于“字符数组”的。在C语言中,字符数组是一个数组,其元素类型为char。例如: char arr[] = "Hello"; // 这是一个字符数组,在栈上分配内存 如果有一个已经存在的字符数组,然后将一个char指针指向它,那么会发生什么? 分析: 1. 字符数组本身已经分配了内存(可能在栈上,也可能在堆上,取决于数组的声明方式)。 2. 将指针指向这个数组,只是让指针存储了数组的首地址,而不会为数组内容重新分配新的内存。也就是说,指针只是指向了已经存在的内存块。 因此,结论是:不会自动分配新的内存,指针只是指向了数组的现有内存。 但是,用户可能混淆了“字符数组”“字符串字面量”的区别。我们需要注意: 情况1:指针指向一个栈上的字符数组 char arr[10] = "Hello"; char *p = arr; // p指向arr数组的首地址,没有新的内存分配,parr共享同一块内存。 情况2:指针指向一个堆上分配的字符数组 char *arr = malloc(10 * sizeof(char)); strcpy(arr, "Hello"); char *p = arr; // 同样,p指向了arr指向的堆内存,没有新的分配。 情况3:指针指向一个字符串字面量(注意:这不是字符数组,而是字符串常量) char *p = "Hello"; // p指向只读存储区,没有动态分配,也不可修改。 情况4:指针指向一个字符数组的初始化(此时字符数组的初始化会分配内存,但指针赋值时不会再次分配) char arr[] = "Hello"; // 这里arr数组在栈上分配了6个字节(包括'\0') char *p = arr; // 指针p指向arr,没有额外分配。 因此,当将char指针赋值给一个已经存在的字符数组时,不会分配新的内存。指针只是获得了该数组的起始地址。 但是,有一种情况需要注意:如果使用数组的地址来初始化一个指针,并且这个数组是字符串字面量,那么实际上指针指向的是字符串字面量(如果直接使用字符串字面量初始化指针的话)?实际上,我们看下面的例子: char arr[] = "Hello"; // 这里arr是一个数组,初始化的内容来自字符串字面量,但数组arr在栈上拥有这个字符串的副本。 char *p = arr; // p指向栈上的数组arr 而如果是: char *p = "Hello"; // p直接指向只读存储区的字符串字面量 两者有本质区别。 所以,回答用户的问题:将char指针指向一个已经存在的字符数组(无论是栈上还是堆上)时,不会自动分配新的内存。指针只是指向了数组的起始地址,共享同一块内存。 另外,我们需要注意,如果这个字符数组是在栈上分配的,那么当数组离开作用域时,指针就会变成悬垂指针(dangling pointer)。例如: char *p; { char arr[10] = "Hello"; p = arr; } // 此时arr的作用域结束,arr的内存被回收,p成为悬垂指针,使用p会导致未定义行为。 同样,如果字符数组是在堆上分配的,那么需要确保在释放内存后不再使用指针。 最后,我们还可以提到,如果希望指针指向的内容独立于原数组,那么需要手动分配内存并复制内容(例如使用strdup函数,但注意strdup不是标准C函数,但很常见)。 总结: - 指针赋值操作(如 char *p = arr;)不会分配新内存,只是地址复制。 - 如果需要独立副本,必须显式分配内存并复制字符串(使用mallocstrcpy,或strdup)。 根据用户上一次的问题,我们还需要强调字符串字面量字符数组的区别。 引用[2]中的内容提到关于数组越界的问题,我们可以借此提醒:如果指针指向的数组被越界访问,可能会破坏内存(例如在调试分配器中会检测到)。所以使用指针操作数组时,要确保不越界。 因此,回答结构如下: 1. 直接回答问题:不会自动分配内存。 2. 解释指针赋值操作的本质(地址复制)。 3. 区分字符数组字符串字面量。 4. 注意事项(作用域、悬垂指针、越界访问)。 5. 如何正确复制字符串(如果需要独立内存)。 我们还可以生成相关问题。 注意:用户提供的引用[1][2]与当前问题关联不大,但引用[2]关于数组越界的问题可以作为一个注意事项提及。 回答如下:</think>在 C 语言中,当您将 `char` 指针指向一个字符数组时,**不会自动分配新的内存**。以下是详细解释: ### 1. **指针赋值本质是地址传递** - 字符数组(如 `char arr[] = "12345678";`)在声明时已分配内存(栈内存)。 - 将指针指向该数组: ```c char arr[] = "12345678"; // 数组在栈上分配内存 char *res_string = arr; // 指针直接指向数组首地址 ``` - **结果**: `res_string` 仅存储 `arr` 的地址(如 `0x7ffd...`),无新内存分配。 `res_string` `arr` 共享同一块内存,修改任一变量会影响另一方。 ### 2. **与字符串字面量的关键区别** - 若直接指向字符串字面量: ```c char *res_string = "12345678"; // 指向静态存储区(只读) ``` - 字符串字面量存储在**只读内存段**(编译时分配),不可修改[^1]。 - 仍无动态内存分配(如 `malloc`)。 - **危险操作**: ```c res_string[0] = 'a'; // 尝试修改 → 段错误(未定义行为) ``` ### 3. **需要独立内存时的正确做法** - **方法 1:显式动态分配** ```c char *res_string = malloc(9 * sizeof(char)); // 分配堆内存 if (res_string != NULL) { strcpy(res_string, "12345678"); // 复制内容 } // 使用后需手动释放: free(res_string); ``` - **方法 2:使用栈数组 + 指针** ```c char arr[] = "12345678"; // 栈数组(可修改) char *res_string = arr; // 指针指向栈内存 ``` - 注意:`arr` 离开作用域后,`res_string` 会变成悬垂指针。 ### 4. **关键注意事项** - **无自动内存管理**:C 语言要求开发者显式控制内存[^2]。 - **越界风险**: 若通过指针越界访问(如 `res_string[20] = 'x'`),可能破坏相邻内存,导致未定义行为(调试器可能捕获此类错误[^2])。 - **只读约束**: 指向字符串字面量的指针应声明为 `const`: ```c const char *res_string = "12345678"; // 明确只读意图 ``` ### 总结 | 场景 | 是否分配新内存 | 内存区域 | 是否可修改 | |----------------------------------|----------------|------------|------------| | `char *p = 现有数组;` | ❌ 否 | 栈/堆 | ✅ 是 | | `char *p = "12345678";` | ❌ 否 | 静态只读段 | ❌ 否 | | `char *p = malloc(n); strcpy(...)` | ✅ 是 | 堆 | ✅ 是 | > 始终优先使用 `char[]` 或动态分配来存储需修改的字符串,避免直接赋值给指针导致未定义行为。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lm_y

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值