字符数组是C中表示字符串常量的另一种方式吗?

字符数组是C中表示字符串常量的另一种方式吗?,c,arrays,string,C,Arrays,String,我们可以说上面的HELLO是一个字符串常量吗?我对此有疑问,因为我们可以更改字符串元素,比如a[0]='a'。那么,我们是否仍然可以在这里将“HELLO”声明为字符串常量,仅仅因为它的末尾包含一个NULL。字符串是以null结尾的字符数组。字符串常量必须是不可变的。当字符串出现在双引号定义的代码中时(例如,“hello”),它被视为字符串文字。内存中的实际字符数组将是一个字符串。不,这不是C中的字符串常量。顺便说一下,C语言中的任何字符串都必须以“\0”结尾,例如: char a[ ]= "HE

我们可以说上面的HELLO是一个字符串常量吗?我对此有疑问,因为我们可以更改字符串元素,比如
a[0]='a'
。那么,我们是否仍然可以在这里将“HELLO”声明为字符串常量,仅仅因为它的末尾包含一个
NULL
。字符串是以null结尾的字符数组。字符串常量必须是不可变的。当字符串出现在双引号定义的代码中时(例如,
“hello”
),它被视为字符串文字。内存中的实际字符数组将是一个字符串。

不,这不是C中的字符串常量。顺便说一下,C语言中的任何字符串都必须以“\0”结尾,例如:

char a[ ]= "HELLO";
如果要在C代码中添加字符串常量,以下是一个示例:

// '\0' explicitly included as the last element
char str[] = "HELLO";  

// '\0' has to be the last element in this case
char str2[] = {'H', 'E', 'L', 'L', 'O', '\0'}; 
常量字符串的另一个示例:

const const_str[] = "HELLO";
没有

常量是在程序执行过程中不会改变(或不应该改变)的变量。只要你能做a[1]=“d”它不是一个常数

要在c中定义常量字符串,可以采用三种方法:

#define CONST_STR "HELLO"
其他定义不会创建常量字符串,而是可变字符数组,这是另一回事。

是的,
“HELLO”
仍然是字符串常量(更具体地说,它是字符串文字)

但是,数组
a
,其内容被初始化为该常量的副本,而不是。

“HELLO”
是一个字符串文字-它被存储为
字符的数组,在程序的生命周期内可用。它可能存储在只读内存段中,具体取决于实现(在我的系统上是)。试图修改字符串文字的内容会导致未定义的行为

a
不是字符串文字-它是用字符串文字的内容初始化的
char
数组
“HELLO”
。您可以根据自己的意愿更改
a
的内容(尽管不能存储长度超过5个字符的字符串)

下面是一个简短的程序,用于显示字符串literal
“HELLO”
和数组
a
之间的关系(以及为便于测量而抛出的指针):

字符串文本“HELLO”
存储为ASCII(或UTF8)字符序列,从地址
0x400b30
开始

数组
a
从地址
0x7fff89062330
开始存储-如您所见,它包含字符串
“HELLO”
的副本

指针
p
从地址
0x7fff89062328
开始存储-它存储字符串文本的地址
“HELLO”
(x86是小尾端,因此多字节值从最低有效字节开始存储-您需要从右到左、从下到上读取)

您注意到的一点是
“HELLO”
与变量
a
p
之间的地址差异。在我的系统中,
“HELLO”
存储在
.rodata
内存段中:

       Item         Address   00   01   02   03
       ----         -------   --   --   --   --
    "HELLO"        0x400b30   48   45   4c   4c    HELL
                   0x400b34   4f   00   22   48    O."H

          a  0x7fff89062330   48   45   4c   4c    HELL
             0x7fff89062334   4f   00   00   00    O...

          p  0x7fff89062328   30   0b   40   00    0.@.
             0x7fff8906232c   00   00   00   00    ....
$objdump-j.rodata-d strings2
strings2:文件格式elf64-x86-64
节段的拆卸。rodata:
0000000000 400B2C:
400b2c:01 00 02 00 48 45 4c 4f 0022 48 45 4c 4f…您好。“您好”
400b3c:2200610070004164726573004974。
...

a
p
从运行时堆栈分配,运行时堆栈从高地址开始,向下向低地址增长

“HELLO”是一个字符串常量
a
是从字符串常量初始化的
char
s数组。C或C++?在C++ <代码>“text”<代码>中称为字符串literal@NathanOliver:C99§6.4.5也将其称为字符串文字。@BoundaryPositionCool。谢谢不确定C是否调用了相同的东西。或者
const char*str=“test”。将宏引入其中只是混淆了问题。
const char*WHATEVER=“HELLO”
是最简单、最安全和最快的(总的来说)。@BoundaryPosition仍然使其
静态
限制了文件的范围,因此有时它比普通的
常量
变量更安全。对于宏,是的,声明一个
const
值比声明一个宏更安全,因为它们是在预处理器中处理的,并且不是类型安全的。我想指出的主要区别是
*
[]
,因为您生成了一个不需要的副本。@BoundaryPosition我的错,没有看到
*
#include <stdio.h>
#include "dumper.h"

int main( void )
{
  char a[] = "HELLO";
  char *p = "HELLO";

  char *names[] = { "\"HELLO\"", "a", "p" };
  void *addrs[] = { "HELLO", a, &p };
  size_t sizes[] = { sizeof "HELLO", sizeof a, sizeof p };

  dumper( names, addrs, sizes, 3, stdout );

  return 0;
}
       Item         Address   00   01   02   03
       ----         -------   --   --   --   --
    "HELLO"        0x400b30   48   45   4c   4c    HELL
                   0x400b34   4f   00   22   48    O."H

          a  0x7fff89062330   48   45   4c   4c    HELL
             0x7fff89062334   4f   00   00   00    O...

          p  0x7fff89062328   30   0b   40   00    0.@.
             0x7fff8906232c   00   00   00   00    ....
$ objdump -j .rodata -d strings2

strings2:     file format elf64-x86-64

Disassembly of section .rodata:

0000000000400b2c :
  400b2c:       01 00 02 00 48 45 4c 4c 4f 00 22 48 45 4c 4c 4f     ....HELLO."HELLO
  400b3c:       22 00 61 00 70 00 41 64 64 72 65 73 73 00 49 74     ".
  ...