char *str 与char str[]的区别与联系

news2024/9/22 21:26:06

char *str 与char str[]的区别与联系

常用以下两种方式定义字符串:一种是字符数组,另一种是指向字符串的指针。


文章目录

  • char *str 与char str[]的区别与联系
  • 一、基本概念区别
  • 二、名称含义区别
  • 三、底层属性区别
      • 1.char *str = "abcdefgh"
      • 2.char str[] = "stuvwxyz"
  • 四、作为函数参数
  • 五、作函数返回值
  • 六、其他区别


一、基本概念区别

char *str:声明的是一个字符型指针,这个指针可指向任何字符串常量或某个字符变量。
char str[] :声明的是一个字符型数组,数组的内容可以是任何内容,末尾加上’\0’ 后就是是字符串。

二、名称含义区别

char *str:str是一个字符型指针变量,这个指针变量用来保存某个字符变量或常量的地址(定义字符串时,保存首字符地址)
char str[] :str是数组名,数组名的值是一个指针常量,也就是该数组第一个元素的地址。数组名用于表达式中时,编译器将它视为一个指针常量。

对于数组名的理解,可参见C语言的经典书籍《Pointers On C》(Kenneth.A Reek) 【US】中文版,译名:《C和指针》,其中对数组名的理解有这样一段描述:指针常量指向的是内存中数组的起始位置,如果要修改这个指针常量,唯一可行的操作就是把数组移动到内存其他位置,但是,当程序完成链接之后,内存中数组的位置是固定的,所以程序运行时,再想要移动数组为时已晚了,因此数组名的值是一个指针常量。

三、底层属性区别

数组和指针都可以在定义时使用字符串常量对其进行初始化:
char *str = “abcdefgh”;
char str[] = “stuvwxyz”;
两者看似一样,但底层机制有很大区别。

1.char *str = “abcdefgh”

char *str = “abcdefgh”,定义了一个指向字符串常量的指针,编译过后,是不运行再通过指针修改字符串的值,但是str变量却可以改变指向。见下代码:字符串"abcdefg"作为常量保存在静态存储区,其位置在编译后已经固定,str1和str2指向同一个字符串常量首字符的地址,所以打印的值和地址都是一样的。此时改变str指向,使其指向另一个字符串常量"ABCDEFG",值和地址都改变。

void main()
{
       char *str1 = "abcdefg";
       char *str2 = "abcdefg";
       printf("*str1 = %s \t &str1[0] = %p \n",str1,&str1[0]);
       printf("*str2 = %s \t &str2[0] = %p \n",str2,&str2[0]);
       str2 = "ABCDEFG";
       printf("*str2 = %s \t &str2[0] = %p \n",str2,&str2[0]);
 }

运行结果:
在这里插入图片描述

因为在ANSIC中,初始化指针时所创建的字符串常量被定义为只读,如果试图通过指针修改字符串的值,会出现未定义错误,所以如果写成:str2[1] = ‘B’,则会出现编译没问题,运行出现段错误。
因此在这种定义字符串的方式中,我们可以将str看作常量指针,因为常量指针定义完成后不可修改指向地址中的值,但可修改其指向的地址。

值得一提的是,在实际项目中,为了防止这个指针变量乱指方向,一般在定义时会加上const修饰这个变量:
char *const str = “abcdefgh”;如此一来,其指向也就不能变了,用该变量特指该字符串常量。

2.char str[] = “stuvwxyz”

char str[] = “stuvwxyz”:声明的是一个字符型数组,数组的内容可以是任何内容,末尾加上’\0’ 后就是是字符串。这种定义方式,数据保存全局数据区或堆栈区,可以看到虽然str1和str2的内容字符串都一样,但是地址却不一样,所以大胆推测其内容应该是可以修改的,验证代码如下:

void main()
{
      char str1[] = "stuvwxyz";
      char str2[] = "stuvwxyz";
      printf("*str1 = %s \t &str1[0] = %p \n",str1,&str1[0]);
      printf("*str2 = %s \t &str2[0] = %p \n",str2,&str2[0]);
      str2[1] = 'T';
      printf("*str2 = %s \t &str2[0] = %p \n",str2,&str2[0]);
}                                                  

运行结果:
在这里插入图片描述

可以看到str2的第二个字符已经变成大写’T’,但是如果写成:str2 = ‘STUVWXYZ’,则会出现编译问题。因此关于数组名str,我们可看为一个指针常量,因为指针常量定义完成后可修改指向地址中的值但不可修改其指向。

四、作为函数参数

二者作为函数参数时的特征几乎无区别,这主要体现在以下两方面:
1:数组名作为参数传递给函数时,实际上传递给函数的是指向数组第一个字符的指针。因此都可以看做是指针作为参数传递,对指针参数执行间接访问操作是允许函数修改原先的数组元素的,但是函数所接收到的参数是原参数的一份拷贝,所以函数对参数进行操作而不会影响实际的参数,说明白点就是函数内无法改变指针参数的指向,但可以改变指针参数所指向的值
2:数组形参即可声明为数组形式,也可申明为指针形式,这两种申明形式只有当它们作为函数形参时才是相等的。

#include<stdio.h>
#include<stdlib.h>
 
void fun(char *s1,char s2[]) //两种声明形式都可以
{
         s2[1] = s1[1];
         s1 = "Hello world!"; 
}
void main()
{
        char str2[] = "stuvwxyz";
        char *str1 = "ABCDEFG";
        fun(str1,str2);      
        printf("str1 = %s \t str2 = %s \n",str1,str2);
}

结果:s1指向没该变,s2第二个元素已改变
在这里插入图片描述

提示:如果要在函数中改变传入的指针实参的值需要解引用或使用二级指针:

五、作函数返回值

都可以通过名称作为实参传入函数内部,但其基本属性保持不变,但作为函数返回值返回时候,直接在函数内部定义字符串数组char str[],然后返回str是不行的,因为此时定义的字符串数组是在栈区,函数结束后该函数栈区被释放,str指向的区域为空,返回值是无效的,如下,函数fun返回str1是无效的,返回str3是有效的。

#include <stdio.h>
#include <stdlib.h>

char *fun()
{
	char str1[] = "stuvwxyz";
	char *str3 = "abcdefghijk";
	return str1;
}
int main(int argc, char **argv)
{   
     char *str = fun(2);
     printf("str = %s \n",str);
     
     return 0;
}

其他情况下要在函数内使用数组或指针,需要用new或者malloc函数申请堆空间,然后在外部使用之后释放,

六、其他区别

一般情况下数组名和指针可以通用,但是除了上述区别以外还有两个例外:

1.sizeof(数组名字)得到的是数组大小所占字节空间;sizeof(指针变量名)得到的是指针本身所占的字节空间。
2.&数组名:得到指向整个数组的指针,&数组名+1会跳跃整个数组;&指针变量名得到指向指针变量的地址。

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

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

相关文章

MDK 5.xx.0 + STM32F10x 笔记

天才脑袋比不上烂笔头, 写给自己看, 自用资料。 安装MDK STM32环境 Download MDK安装 MDK -> c:\keil_v5 用默认路径下载 ARMCC V5.06 Update 7 (build960) <- 长期稳定支持版本安装至 c:\keil_v5\arm\ARMCC开启 uVision.设定 预设编译程序版本 : V5.06 Update 7 (bui…

C# 学习笔记--个人学习使用 <1>

C# 学习笔记 Chapter 1 C# 比较软的基础部分Section 1 类与命名空间Part 1 命名空间 NameSpacePart 2 类 Class Section 2 基本元素Section 3 数据类型Part 1 什么是类型&#xff1f;Part 2 类型在 C Sharp 中的作用Part 3 C Sharp 中的数据类型 Section 4 变量、对象与内存Par…

GIthub 无法访问使用Watt Toolkit加速

一、使用 Watt Toolkit Watt Toolkit 是一款加速软件&#xff0c;原名是 Steam&#xff0c;后来改名为 Watt Toolkit&#xff0c;其可以让原本无法访问的 Steam 游戏社区、 GitHub 、谷歌验证码等国内难以访问的网页正常访问。 三种下载方式&#xff1a; Watt Toolkit 官网下…

STM32的时钟系统

今天&#xff0c;学习了STM32的时钟系统&#xff0c;如下为stm32的时钟树。

[牛客复盘] 牛客周赛 Round 9 20230827

[牛客复盘] 牛客周赛 Round 9 20230827 总结小美的外卖订单编号1. 题目描述2. 思路分析3. 代码实现 小美的加法1. 题目描述2. 思路分析3. 代码实现 小美的01串翻转1. 题目描述2. 思路分析3. 代码实现 小美的数组操作1. 题目描述2. 思路分析3. 代码实现 六、参考链接 总结 又是…

Linux c++开发-02-g++命令行编译

有如下的文件目录结构 格式一 swap.h swap.cpp main.cpp 编译方法和结果如下&#xff1a; 格式二 swap.cpp main.cpp 使用命令&#xff1a;g main.cpp src/swap.cpp -o main.exe 解决方法使用参数 -I 格式三-将swap.cpp生成一个静态库然后链接到main.cpp中 生成…

某人事系统架构搭建设计记录

首发博客地址 https://blog.zysicyj.top/ 先大致列一下基础情况 架构必须是微服务 场景上涉及大量查询操作&#xff0c;分析操作 并发并不高 对高可用要求较高&#xff0c;不能挂掉 对安全要求高 要能过等保测试等三方测试 使用人数并不多&#xff0c;十万内 涉及很多在线编辑&…

多线程学习之解决线程同步的实现方法

一、卖票的多线程实现 需求&#xff1a;共有100张票&#xff0c;而它有3个窗口卖票&#xff0c;请设计一个程序模拟该电影院卖票 代码实现&#xff1a; /*** Author&#xff1a;kkoneone11* name&#xff1a;SellTicket1* Date&#xff1a;2023/8/26 11:32*/ public class S…

mit s0681 lab2 Trace系统调用实现

实验一 实现一个用户级别的程序&#xff0c;功能为&#xff0c;指定系统调用后&#xff0c;跟踪程序的系统调用情况 分析实验 实验目标为实现一个程序去跟踪指定程序的系统调用。因此目标有两个 实现一个程序跟踪目标程序的系统调用 实现1&#xff0c;就需要在用户这边实…

六、Json 数据的交互处理

文章目录 一、JSON 数据的交互处理1、为什么要使用 JSON2、JSON 和 JavaScript 之间的关系3、前端操作 JSON3.1 JavaScript 对象与 JSON 字符串之间的相互转换 4、JAVA 操作 JSON4.1 Json 的解析工具&#xff08;Gson、FastJson、Jackson&#xff09;4.2 ResponseBody 注解、Re…

爬虫(bilibili热门课程记录)

什么是爬虫&#xff1f;程序蜘蛛&#xff0c;沿着互联网获取相关信息&#xff0c;收集目标信息。 一、python环境安装 1、先从Download Python | Python.org中下载最新版本的python解释器 2、再从Download PyCharm: Python IDE for Professional Developers by JetBrains中下…

关于msvcp140.dll丢失的解决方法,分享最简单详细的解决方法

今天&#xff0c;我将为大家详细介绍一种常见的问题——msvcp140.dll丢失&#xff0c;并提供四种不同的解决方法。希望通过这次分享&#xff0c;能够帮助大家解决这个问题&#xff0c;提高电脑使用效率。 首先&#xff0c;让我们来了解一下msvcp140.dll文件。msvcp140.dll是Mi…

JavaScript中的事件循环(Event Loop)

1. 概述 javaScript是单线程的&#xff0c;意味着它一次只能执行一个任务。然而&#xff0c;许多操作&#xff0c;如网络请求、定时器等&#xff0c;都会导致延迟&#xff0c;如果程序在等待这些操作完成时&#xff0c;可能会操作一个阻塞的效果&#xff0c;影响用户体验。这个…

设计模式之命令模式(Command)的C++实现

1、命令模式的提出 在软件开发过程中&#xff0c;“行为请求者”和“行为实现者”通常呈现一种“紧耦合”&#xff0c;如果行为的实现经常变化&#xff0c;则不利于代码的维护。命令模式可以将行为的请求者和行为的实现者进行解耦。具体流程是将行为请求者封装成一个对象&…

Git企业开发控制理论和实操-从入门到深入(六)|多人协作开发

前言 那么这里博主先安利一些干货满满的专栏了&#xff01; 首先是博主的高质量博客的汇总&#xff0c;这个专栏里面的博客&#xff0c;都是博主最最用心写的一部分&#xff0c;干货满满&#xff0c;希望对大家有帮助。 高质量博客汇总 然后就是博主最近最花时间的一个专栏…

c语言实现堆

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、树1、树的概念2、树的相关概念3、树的表示 二、二叉树1、二叉树概念2、特殊的二叉树3、二叉树的性质4、二叉树的顺序结构5、二叉树的链式结构 三、堆(二叉树…

基于VHDL语言的汽车测速系统设计_kaic

摘 要 汽车是现代交通工具。车速是一项至关重要的指标。既影响着汽车运输的生产率,又关乎着汽车行驶有没有超速违章&#xff0c;还影响着汽车行驶时人们的人身安全。而伴随着我国国民的安全防范意识的逐步增强&#xff0c;人们也开始越来越关心因为汽车的超速而带来的极其严重…

2005-2022年全国各地级市经济增长目标约束

2005-2022年全国各地级市经济增长目标约束 1、时间&#xff1a;2005-2022年 2、来源&#xff1a;政府工作报告 3、指标&#xff1a;省份、城市、年份、经济增长目标硬约束、经济增长目标软约束 4、范围&#xff1a;地级市&#xff0c;每年具体城市数量参看下面图片 5、指标…

C语言_通过函数调用改变指针参数的指向

C语言_通过函数调用改变指针参数的指向 函数的参数为指针类型&#xff0c;对一般指针参数执行间接访问操作是允许函数修改原先的数组元素的&#xff0c;但是函数所接收到的参数是原参数的一份拷贝&#xff0c;所以函数对参数进行操作而不会影响实际的参数&#xff0c;就是说正常…

深度学习在自然语言处理中的十大应用领域

文章目录 1. 机器翻译2. 文本分类3. 命名实体识别4. 问答系统5. 文本生成6. 情感分析7. 语言生成与处理8. 信息检索与摘要9. 文本纠错与修复10. 智能对话系统总结 &#x1f389;欢迎来到AIGC人工智能专栏~深度学习在自然语言处理中的十大应用领域 ☆* o(≧▽≦)o *☆嗨~我是IT陈…