你知道char *s和char s[]的区别吗?

在一个夜深人静的晚上,有一个读者给我发了一个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学习资料

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/467903.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

5类主题词汇(4)

求职就业类 unemployment失业 job-hunting找工作 position职位 job resume就业简历 job interview工作面试 job prospects职业背景application letter求职信 the want ads招聘工作 fill in/out application form填写申请表 accept/take the post接受职位 take over the post接…

python连连看小游戏_利用Python制作一个连连看小游戏,边学边玩!

导语今天我们将制作一个连连看小游戏&#xff0c;让我们愉快地开始吧~开发工具Python版本&#xff1a;3.6.4相关模块&#xff1a;pygame模块&#xff1b;以及一些Python自带的模块环境搭建安装Python并添加到环境变量&#xff0c;pip安装需要的相关模块即可。先睹为快在cmd窗口…

上Google Adsense个人的一点体验

最近我想开通一个Google Adsense帐号&#xff0c;因为以前注册过一个Google帐号&#xff0c;所以我以为两个是可以共通的&#xff0c;因为很久没上Google帐号&#xff0c;我记不太清密码了&#xff0c;所以我先是登录了Google&#xff0c;登上去了&#xff0c;密码没记错。然后…

通俗易懂,嵌入式Linux驱动基础

前言上一篇分享的&#xff1a;《从单片机工程师的角度看嵌入式Linux》中有简单提到Linux的三大类驱动&#xff1a;我们学习编程的时候都会从hello程序开始。同样的&#xff0c;学习Linux驱动我们也从最简单的hello驱动学起。驱动层和应用层 还记得实习那会儿我第一次接触嵌入式…

记,我在深圳买房

今天晚上&#xff0c;有点时间&#xff0c;把这次买房的经历写下来。我并不是想炫耀&#xff0c;也不是想说明什么&#xff0c;只是为了记录自己的生活。这是对自己的一个阶段性总结&#xff0c;也希望自己的意见和想法对读者们有些帮助。再者&#xff0c;凭自己的努力&#xf…

tif 高程_使用ArcGIS提取高程点

地球表面形状的最常见数字化数据便是基于像元的数字高程模型(DEM)&#xff0c;该数据可用作量化地表特征的输入。DEM属于一种连续表面的栅格制图表达&#xff0c;通常参考真实的地球表面&#xff0c;有的时候除了需要DEM还需要高程点&#xff0c;这里讲解一下如何使用ArcGIS从D…

《三毛。。。。》烂漫

&#xff08;初衷&#xff09;三毛&#xff0c;一个家喻户晓的人物&#xff0c;可她毕竟还不是流浪的三毛&#xff0c;她有深爱她的丈夫&#xff0c;父母&#xff0c;堂哥。。。。 &#xff08;概述&#xff09;本书介绍了三毛的人生遭遇&#xff0c;三毛还将自己的人生体验写成…

5类主题词汇(5)

日常应用类 complaint投诉 lodge the complaint投诉 fake products假冒产品 apply for 申请 apologize for 道歉 heartfelt welcome由衷地欢迎 letter of recommendation推荐信 decline a job offer婉拒工作机会 heartiest congratulation最衷心的祝贺 a farewell letter告别信…

你试试用心呼吸

我曾经历过掉水里&#xff0c;两次。第一次&#xff0c;是在水上乐园&#xff0c;不会游泳的我&#xff0c;从高滑梯上头朝下扎到水中。一下子&#xff0c;就感觉呼吸不了&#xff0c;非常惊恐&#xff0c;然后有人&#xff08;救生员&#xff09;揽住了我&#xff0c;我非常惊…

cython python3_30倍!使用Cython加速Python代码

原标题&#xff1a;30倍&#xff01;使用Cython加速Python代码作者&#xff1a;George Seif、Thomas Wolf、Lukas Frei编译&#xff1a;116 | 公众号海外部前言你可能经常会一次又一次地听到关于Python的抱怨&#xff0c;Python跑起来太慢了&#xff01;与许多其他编程语言相比…

Git安装及密钥的生成并上传本地文件到GitHub上

之前用的GitHub&#xff0c;不太熟练&#xff0c;一直在上传的过程中遇到了一些问题&#xff0c;看了网上诸多教程&#xff0c;总觉得很乱&#xff0c;特参考一些资料&#xff0c;总结了一篇完整的操作步骤&#xff0c;从下载安装到上传文件&#xff0c;亲测有效1.下载Git软件&…

100条常用写作谚语(1)(2)(3)(4)

文章目录勤奋 意志与成功学习方法与态度健康与心态品行与操守勤奋 意志与成功 where there is a will&#xff0c;there is a way有志者事竟成 No pains&#xff0c;no gains没有付出没有收获 Constant dropping wears away a stone水滴石穿&#xff0c;绳锯木断 Care and dil…

声明为数组定义为指针,声明为指针定义为数组

导语在这里我们做种强调的是在两个文件中&#xff0c;定义为数组声明为指针和定义为指声明为数组的这辆中情况。那么我们就需要两个源文件test.c和main.c。定义为数组&#xff0c;声明为指针test.cchar arr[] "abcdef";main.c#define _CRT_SECURE_NO_WARNINGS 1 #in…

100条常用写作谚语(5)(6)(7)(8)

文章目录金钱与财富珍惜时光择友与友谊常理与法则金钱与财富 Gold will not buy anything黄金不能买一切 The chief aim of man is not to get money 人的主要目的不是赚钱 The money the miser hoards will do him not good 守财奴积财&#xff0c;对自己毫无好处 What is we…

python中内置的集成开发工具_python应用(3):启用集成开发工具pycharm

之前写了个python程序给自己用&#xff0c;写代码时用的是macvim(vim的一种)&#xff0c;macvim是个编辑工具&#xff0c;由于我已经设置过对python等各种语言的支持特性&#xff0c;所以什么缩进、对齐、高亮之类的表现都有&#xff0c;写起代码来非常舒服。可是&#xff0c;不…

python selenium环境配置Firefox和Chrome

1、下载Selenium库&#xff0c;可以使用pip install selenium https://pypi.python.org/pypi/selenium/ 2、下载驱动 Chrome: https://sites.google.com/a/chromium.org/chromedriver/downloads Firefox: https://github.com/mozilla/geckodriver/releases 3、配置环境变量 需要…

BUG_ON()、panic()、dump_stack()几种内核调试手段

Linux内核有一些方法可以用来方便标记bug&#xff0c;提供断言并输出信息。最常用的两个是BUG()和BUG_ON()。当被调用的时候&#xff0c;它们会引发oops&#xff0c;导致栈的回溯和错误信息的打印。这些声明会导致 oops跟硬件的体系结构是相关的。大部分体系结构把BUG()和BUG_O…

wordvba编程代码大全_这几本基础编程书籍一定要看

程序员书库(ID&#xff1a;OpenSourceTop) 编译书单来自&#xff1a;https://simpleprogrammer.com/best-programming-books-2019/关于程序员类的技术书籍有很多&#xff0c;但是往往没有时间阅读&#xff0c;下面的这些书籍&#xff0c;由John Sonmez精选&#xff0c;可以帮助…

经典DP

1.背包问题 &#xff08;1&#xff09;01背包 从n个重量和价值分别为wi,vi的物品&#xff0c;从中选出不超过W的物品&#xff0c;每种物品仅有一件&#xff0c;求所有方案中V的最大值。 最朴素最简单也最费时的方法&#xff1a;O(2^n) int rec(int i,int j)//从第i个开始挑选总…

C语言、嵌入式重点知识:回调函数

前言 上文分享了一个专用的双链表的基本操作示例&#xff1a;双链表的操作示例&#xff08;附代码&#xff09;这里提到了一个关键词&#xff1a;专用。与专用对应的词是通用。我们从字面上可以很容易理解这两个词&#xff0c;专用就是针对特定情况的&#xff0c;特点就是很有局…