char s1[] = "hello";
char* s2 = "hello";
- 编译器在栈上为数组s1分配连续内存,数组的内容也就是元素可以修改
- s2中的hello是字符常量,在内存分配上,分配到了rodata段,也就是只读区,指针s2在栈上分配内存,并指向这个只读区的地址
- s2本身是指针,可以改变,即可以指向另一个字符串,但字符串字面值的内容不可以被修改
所以
s1[0] = 'H'; //正确
s2[0] = 'H'; // 错误,段错误
- 其次,s1是数组,其大小是整个数组的大小:6,s2是指针,大小是指针的大小:8
- s1本身是数组名,是第一个元素的地址,是常量,s2本身是指针,是变量,这就好比指针常量和常量指针
所以
s1++; //错误
s2++; // 正确
看如下代码
char* func(){
char s1[] = "hello";
char* s2 = "hello";
return s1;
return s2;
}
哪个可以被正确return呢
s1
是一个局部字符数组,定义在栈上,这个数组的生命周期是函数 func
的作用域。一旦函数返回,这个数组的内存会被释放,返回指向这个数组的指针会导致指针悬空。
s2
是一个指针,指向一个字符串常量,字符串常量的生命周期贯穿程序的整个运行期。因此,返回这个指针是安全的
结论:
char* func() {
char s1[] = "hello";
char* s2 = "hello";
// return s1; // 不安全
return s2; // 安全
}
所以
通常不返回字符数组,而是
函数参数中传递一个预分配的字符数组,然后在函数中填充它。
使用string自动管理内存
ps:传入为char a[10]这样的char * 型数组,函数参数为char * 类型接收,同理返回char a[10]用char * 接收, 此时要接受char *的函数参数时,是声明char *的指针指向它的。
番外:
写一个用指针swap函数交换值
void swap(int* a, int* b){
int temp = *b; // 必须用int的临时变量存储b的值,不能使用int* temp = b;
*b = *a;
*a = temp;
}
写一个用指针swap函数交换指针
void swap(int** a, int** b){
int* temp = *b; // 必须用int*的临时变量存储b的值,不能使用int** temp = b;
*b = *a;
*a = temp;
}
完整代码:
#include <cstring>
#include <iostream>
void func(char* buffer, size_t bufferSize) {
const char* message = "hello";
if (bufferSize >= strlen(message) + 1) {
strcpy(buffer, message);
}
}
void swap(int** a, int** b){
int* temp = *b;
*b = *a;
*a = temp;
}
char* func(){
char s1[] = "hello";
char* s2 = "hello";
return s1;
// return s2;
}
int main() {
char buffer[6]; // 预分配数组
func(buffer, sizeof(buffer));
std::cout << buffer << std::endl; // 输出 buffer 内容
int a = 1;
int* aa = &a;
int b = 2;
int* bb = &b;
swap(&aa, &bb);
std::cout << a <<" " << b <<" " << *aa <<" " << *bb << std::endl;
char* str = func();
std::cout << str << std::endl; // 可能输出垃圾值或程序崩溃
std::cout << "111" << std::endl;
return 0;
}