本文主要针对字符数组和字符指针进行对比,其他类型的对比请大家自行试验~
数组和指针如何定义
char *p = "hello world"; // p为字符指针
char buf[] = "hello world"; // buf为字符数组
1.sizeof大小不同,strlen相同
printf("p的sizeof大小:%d\n", sizeof(p)); // 指针的sizeof大小为4(32位设备为4,64位设备为8)
printf("buf的sizeof大小:%d\n", sizeof(buf)); // 数组的大小要计算最后\0,大小为12
printf("p的strlen大小:%d\n", strlen(p)); // strlen的长度为11,到\0为止
printf("buf的strlen大小:%d\n", strlen(buf)); // strlen的长度为11,到\0为止
2.数组内容可修改,指针的内容不可修改
原则1:堆栈区的数据可修改,全局区内容不可修改
原则2:栈区数据在函数结束后会被释放
例1:
// 编译不报错,运行报错
// 原因:"hello world"字符串在字符常量区,栈上变量p存了字符串的地址,而字符常量区的内容是不可变的
p[0] = 'w';
printf("p: %s\n", p);```
// 成功运行,字符串修改为"wello world"
// 原因:"hello world"字符串拷贝到栈区,将首地址存在buf变量中,栈区内容可修改
buf[0] = 'w';
printf("buf: %s\n", buf);
例2:
char * func1() {
char *a = "hello world";
return a + 6;
}
char * func2() {
char a[] = "hello world";
return a + 6;
}
// 成功显示字符串world
// 原因:"hello world"在字符常量区,函数结束不会被释放,回的是常量区字符串首地址+6,可以找到字符串world
printf("指针a: %s\n", func1());
// 显示结果未知(Visual studio中)或程序崩溃(其他的可能结果)
// 原因:数组a在栈区,函数结束后空间被释放掉了,再读取之前返回的内存空间则是随机字符串或者内存不可访问,程序崩溃
printf("数组a: %s\n", func2());
3.函数传递,数组会退化成指针
数组作为形参传递会退化成指针
为什么会有这样的设计呢?
因为数组所占空间可能很大,如果形参用原数组传递的话,需要占用大量的栈空间,在最初的设备中,空间可是很宝贵的~
void func_char(char *temp_p) {
// sizeof为4, strlen为11
printf("temp_p的sizeof大小:%d\n", sizeof(temp_p));
printf("temp_p的strlen大小:%d\n", strlen(temp_p));
}
void func_arr(char temp_buf[]) {
// sizeof为4, strlen为11
// temp_buf已经退化成指针,如果仍然是数组传递的话,此处的sizeof应为12
printf("temp_buf的sizeof大小:%d\n", sizeof(temp_buf));
printf("temp_buf的strlen大小:%d\n", strlen(temp_buf));
}
func_char(p);
func_arr(buf);
附件:全代码
#include <stdio.h>
char * func1() {
char *a = "hello world";
return a + 6;
}
char * func2() {
char a[] = "hello world";
return a + 6;
}
void func_char(char *temp_p) {
// sizeof为4, strlen为11
printf("temp_p的sizeof大小:%d\n", sizeof(temp_p));
printf("temp_p的strlen大小:%d\n", strlen(temp_p));
}
void func_arr(char temp_buf[]) {
// sizeof为4, strlen为11
// temp_buf已经退化成指针,如果仍然是数组传递的话,此处的sizeof应为12
printf("temp_buf的sizeof大小:%d\n", sizeof(temp_buf));
printf("temp_buf的strlen大小:%d\n", strlen(temp_buf));
}
int main()
{
char *p = "hello world"; // p为字符指针
char buf[] = "hello world"; // buf为字符数组
printf("p的sizeof大小:%d\n", sizeof(p)); // 指针的sizeof大小为4(32位设备,64位设备为8)
printf("buf的sizeof大小:%d\n", sizeof(buf)); // 数组的大小要计算最后\0,大小为12
printf("p的strlen大小:%d\n", strlen(p)); // strlen的长度为11,到\0为止
printf("buf的strlen大小:%d\n", strlen(buf)); // strlen的长度为11,到\0为止
// 编译不报错,运行报错
// 原因:"hello world"字符串在字符常量区,栈上变量p存了字符串的地址,而字符常量区的内容是不可变的
//p[0] = 'w';
//printf("p: %s\n", p);
// 成功运行,字符串修改为"wello world"
// 原因:"hello world"字符串拷贝到栈区,将首地址存在buf变量中,栈区内容可修改
buf[0] = 'w';
printf("buf: %s\n", buf);
// 成功显示字符串world
// 原因:"hello world"在字符常量区,函数结束不会被释放,回的是常量区字符串首地址+6,可以找到字符串world
printf("指针a: %s\n", func1());
// 显示结果未知(Visual studio中)或程序崩溃(其他编译器,未尝试,运行的可能结果)
// 原因:数组a在栈区,函数结束后空间被释放掉了,再读取之前返回的内存空间则是随机字符串或者内存不可访问,程序崩溃
printf("数组a: %s\n", func2());
func_char(p);
func_arr(buf);
system("pause");
return 0;
}