在一个夜深人静的晚上,有一个读者给我发了一个C语言题目。他问我,发哥,帮我看看这个代码有什么问题。我看了代码之后,心里一阵恐慌。我自认为我不是C语言高手。但我确实是一个喜欢解决问题的男人。就是在这样的背景驱使下,我写下了这篇文章。

char *str1 = "hello";
char str2[] = "hello";

我们看这两个定义。我们说这个是定义而不是声明,是因为定义在内存里面分配了房子。而声明,只给了个房产证却不给你分房子。

str1 是 char *类型 。它是一个指针,这个指针指向一个字符串。

str2 是 char [] 类型。它是一个数组,他代表了这堆内存空间。

“hello”字符串在内存中是这样存放的

我之前写过一个不同变量地址分配在内存不同区域的文章,有不清晰的可以再回去看看。

str1 str3都是指向字符串的指针,而且这个字符串是保存在字符串常量区的。这个常量区里面的东西是不能被修改的。编译器让他们指向了同一个地址。这个地址保存的东西是 “hello”这个字符串。

大家看看下面这个代码有什么问题?

#include "stdio.h"
#include "stdlib.h"
#include "string.h"int main(void)
{char *str1 = "hello";char *str3 = "hello";char str2[] = "hello";memcpy(str3,"worldtest",strlen("worldtest")+1);printf("str1:%s str3:%s str2:%s\n",str1,str3,str2);str3 = "world";printf("str1:%s str3:%s str2:%s\n",str1,str3,str2);printf("hello,world\n");return (0);
}

memcpy尝试向一个非法的地址拷贝东西,这个是不允许的。为什么说这个地址非法呢?因为字符常量区里面的内容,只可以读,不可以写。

如果改成这样的呢?应该输出什么结果呢?

#include "stdio.h"
#include "stdlib.h"
#include "string.h"int main(void)
{char *str1 = "hello";char *str3 = "hello";char str2[] = "hello";//memcpy(str3,"worldtest",strlen("worldtest")+1);printf("str1:%s str3:%s str2:%s\n",str1,str3,str2);str3 = "world";printf("str1:%s str3:%s str2:%s\n",str1,str3,str2);printf("hello,world\n");return (0);
}

我之前在文章里面讨论一个问题,我们说指针的时候,要说指针变量。指针变量保存的内容是一个地址。既然是变量,那么保存的地址是可以变化的。只要类型符合。都可以保存。

同样的,在上面的例子中,如果我们尝试这样

str1[1] = 'a';

这样也是错误的。这样也是写操作了非法的地址。

试试下面这段代码

#include <stdio.h>
int main(){char* str1="Hello";printf("\nstr1: %s, address: %p, sizeof(str1): %u", str1, str1, sizeof(str1));str1 = "world";printf("\nstr1: %s, address: %p, sizeof(str1): %u", str1, str1, sizeof(str1));return 1;
}

输出


str1: Hello, address: 0000000000404000, sizeof(str1): 8
str1: world, address: 0000000000404031, sizeof(str1): 8
--------------------------------
Process exited after 0.0226 seconds with return value 1
请按任意键继续. . .

通过赋值运算后,str1的值也发生了改变。

但是str2情况会不一样,str2是一个数组。

既然是数组,我们看看这段小代码

#include<stdio.h>
int main(){char str2[] = "hello";printf("\nstr2: %s, address: %p, sizeof(str2): %u", str2, str2, sizeof(str2));str2[2] = 'A';printf("\nstr2: %s, address: %p, sizeof(str2): %u", str2, str2, sizeof(str2));strcpy(str2, "world");printf("\nstr2: %s, address: %p, sizeof(str2): %u", str2, str2, sizeof(str2));return 1;
}

输出日志

str2: hello, address: 000000000062FE10, sizeof(str2): 6
str2: heAlo, address: 000000000062FE10, sizeof(str2): 6
str2: world, address: 000000000062FE10, sizeof(str2): 6
--------------------------------
Process exited after 0.04063 seconds with return value 1
请按任意键继续. . .

送一个图

晚上回来我写了一个小程序。大家看看

#include <stdio.h>
#include "stdlib.h"
#include "string.h"const int a = 1;
const int a1 = 1;
char * s = "hello";int main()
{const int b = 2;const int b1 = 2;char * s1 = "hello";printf("s:%p s1:%p\n",s,s1);printf("a:%p a1:%p b:%p b1:%p\n",&a,&a1,&b,&b1);return 1;
}

输出如下:

s:0000000000404008 s1:0000000000404008
a:0000000000404000 a1:0000000000404004 b:000000000062FE14 b1:000000000062FE10--------------------------------
Process exited after 0.03901 seconds with return value 1
请按任意键继续. . .

可以看到,s,s1,a,a1在一个内存区域。这个内存区域的内容是不允许改变的。如果你对这里的内存区域赋值,就会出现段错误。

但是b和b1这个内存区域大家看看。我们可以写个小代码测试一下。

#include <stdio.h>
#include "stdlib.h"
#include "string.h"const int b = 2;int main()
{const int b1 = 2;int *p = &b1;printf("b1:%d\n",b1);*p = 3;printf("b1:%d\n",b1);return 1;
}

输出:

b1:2
b1:3--------------------------------
Process exited after 0.0403 seconds with return value 1
请按任意键继续. . .

但是我们写成这样呢?

#include <stdio.h>
#include "stdlib.h"
#include "string.h"const int b = 2;int main()
{const int b1 = 2;int *p = &b;printf("b:%d\n",b);*p = 3;printf("b:%d\n",b);return 1;
}

输出:

b:2--------------------------------
Process exited after 3.743 seconds with return value 3221225477
请按任意键继续. . .

如果放到gcc下,可以看到,执行到代码

*p = 3;

会出现段错误。因为访问了不能访问的地址。这也就是我们很多时候给空指针赋值出现段错误的原因。操作了非法的地址。

好了,就瞎BB这么多,如果觉得有用,可以留言一起讨论下。

回复「 篮球的大肚子」进入技术群聊

回复「1024」获取1000G学习资料

你知道char *s和char s[]的区别吗?相关推荐

  1. char*,const char*,string的相互转换 C++

    转:https://www.cnblogs.com/wxmdevelop/p/4567857.html string转const char* string s ="abc"; co ...

  2. char *p 与char p[N]

    数组不是指针,指针也不是数组,这是两个不同的东西,只是在某些场合下,可以进行相似的操作. char a[10] = "Hello"; char *p = "World&q ...

  3. char str[]与char *str的区别

    一个具体例子: main() {char *p="abc123ABC";//char p[]="abc123ABC"int i=0;while(*(p+i)!= ...

  4. char s []和char * s有什么区别?

    在C语言中,可以在这样的声明中使用字符串文字: char s[] = "hello"; 或像这样: char *s = "hello"; 那么区别是什么呢? 我 ...

  5. 无法从“const char [10]”转换为“char *”

    无法从"const char [10]"转换为"char *" 解决方法: 项目属性  c++--> 语言-->  符合模式->> 选择 ...

  6. C++中const char*, string 与char*的转化

    C++中const char*, string 与char*的转化 原文:https://blog.csdn.net/zhang_alongzd/article/details/52790905 版权 ...

  7. char[]数组与char *指针的区别

    char[]数组与char *指针的区别 问题描述 虽然很久之前有看过关于char指针和char数组的区别,但是当时没有系统的整理,到现在频繁遇到,在string,char[], char *中迷失了 ...

  8. 【错误记录】Android NDK 编译报错 ( no known conversion from ‘unsigned char *‘ to ‘const char *‘ )

    文章目录 一.报错信息 二.解决方案 一.报错信息 在 Visual Studio 2019 中编译 Android NDK , 构建方式参考 [Android 逆向]Android 进程注入工具开发 ...

  9. GetMemeory(char *p);GetMemeory(char **p);char* GetMemeory()用法!

    void GetMemeory(char *p) {p=(char*)malloc(100); }void main() {char *str=NULL;GetMemory(str);strcpy(s ...

  10. char s[] 和 char *s 的区别

    第一种: char *a 与char a[] 的区别 char *d = "hello" 中的a是指向第一个字符'a'的一个指针:char s[20] = "hello& ...

最新文章

  1. linux c 文件映射,linuxc试题
  2. C++:String的写时拷贝
  3. 1062. Talent and Virtue (25)
  4. WordPress 查询数据库 操作数据库
  5. c语言求字符串转换成双精度_C语言实现把字符串中的数字转换成整数
  6. 西门子for循环例子_理解JavaScript中的循环缺陷和迭代协议
  7. Ionic3在ts中获取html中值的方法
  8. Nginx设置expires设定页面缓存时间
  9. Audio PCM输出流程(三十三)
  10. eclipse 使用svn导入web项目
  11. 微信小程序布局 左右结构简单例子
  12. UART串口协议简介
  13. 工信部下令5G降价,三大运营商开启5G流量价格战
  14. 线段等分/定长的实现
  15. Kaggle所有量化金融竞赛汇总。
  16. winform 学习笔记
  17. C++-鼠标操作大全
  18. 【Pytest篇】pytest的parametrize之ids参数正文编码问题
  19. C/C++ 的平方和开平方函数
  20. python hook pc微信_python实现微信跳一跳辅助工具步骤详解

热门文章

  1. linux 程序包管理5 编译安装
  2. struts2中文件上传
  3. Linux 脚本、 正则表达式 等
  4. 如何在Word里面自动生成目录
  5. 后端DTO(数据传输对象)与DAO(数据库数据源对象)解耦的好处
  6. GroupID和ArtifactID
  7. 26-- 转换成小写字母
  8. 广东电网计算机专业笔试题目,广东电网笔试题目
  9. activiti 批量 mysql_Activiti6系列(3)- 快速体验
  10. Log 日志的使用与重要性