理解 char array[] 和 string

Posted

技术标签:

【中文标题】理解 char array[] 和 string【英文标题】:Understanding char array[] and string 【发布时间】:2015-06-04 16:23:16 【问题描述】:

我是编程新手。我正在学习 C 作为我的第一门编程语言。我发现了一些奇怪的东西。

我了解到,在 C 语言中,我们可以将字符串表示为这样的字符序列(使用 char 数组):

char status[10] = "Married";   

我了解到这种方法的问题是我们必须在编译期间告诉status数组的大小。

但现在我知道我们可以使用 char 指针来表示 string 之类的 -

char status[10] = "Married";
char *strPtr;
strPtr = status;

我没有正确理解它。我的问题是 -

    如何使用strPtr 获取索引 4 处的字符(即 Married 中的 i)?

    status 中,string 的末尾有一个空字符 (\0),由 char 数组表示 - M-a-r-@987654335 @-i-e-d-\0。所以通过使用空字符(\0)我们可以理解字符串的结尾。当我们使用strPtr时,如何理解string的结尾?

【问题讨论】:

1) *(strPtr+4) 会给你字符i。 2)strPtr 也指向status,所以它最后会有(相同的)空字符(\0)。 由于数组衰减为指向其第一个元素的指针,因此数组和指针通常可以互换使用,因此在数组上使用解引用运算符将​​起作用,就像在指针上使用数组索引运算符一样。此外,*(arrayOrPointer + X) 等价于 arrayOrPointer[X] 检查What does sizeof(&array) return? 【参考方案1】:

我要发表一个挑衅性的声明:考虑这一点的方式是 C 没有字符串C 只有char 的数组。尽管有它的名字,char 实际上是一个 numeric 类型(例如,'A' 只是写数字的一种有趣的方式,通常是 65)。

char 的数组与int 的数组或任何其他数值类型的数组并没有真正的不同;只是该语言提供了一些额外的方法来编写char 类型的对象及其数组,并且有一个通用约定(使用strlen 之类的函数系统化)如何解释存储在char 数组中的数据为字符串的表示。

char status[10];     // declares an array of `char` of length 10. 
char *strPtr;        // declare a pointer to `char`
strPtr = status;     // make `strPtr` point to the first element of `status`

// Declare an array of 6 `char`, and initialize it.
char hello[6] = 'H', 'e', 'l', 'l', 'o', '\0';

// Shorthand notation for initializing an array of 6 `char` as above
char world[6] = "World";

// I want to store numeric data in this one!
char other[6] = 0, 1, 2, 3, 4, 5;

// "World" is shorthand for a constant array of 6 `char`. This is
// shorthand for telling the compiler to actually put that array in
// memory someplace, and initialize worldPtr to point to that memory.
const char *worldPtr = "World";

// This does the same thing as above. But it's still a *constant* array.
// You should *never* do this; it should be syntactically illegal to
// make a nonconstant `char*` to point to it. This is only allowed for
// historical reasons.
char *helloPtr = "Hello";

【讨论】:

【参考方案2】:
char *strPtr;
strPtr = status;

现在您的指针 strPtr 指向数组中的第一个字符,您可以这样做

int i =0;
while( strPtr[i] != '\0')

  printf("%c ",strPtr[i]);
  i++;

*strPtr 被称为解引用指针以获取存储在指针指向的位置的值。

请注意

strPtr[4] = *(strPtr +4); 

两者都会得到存储在数组索引 4 处的值。

注意指针和数组名的区别:

----------------------------------
| s  | t  | r  | i  | n | g | \0 |
----------------------------------
  |
strPtr
status

strPtr ++ 将使您的指针指向数组中的下一个元素。

| s  | t  | r  | i  | n | g | \0 |
----------------------------------
       |
      strPtr

而您不能对数组名称执行此操作

status++ 不允许,因为an array is not a modifiable lvalue。

【讨论】:

哇!这意味着我们可以使用指针名称-strPtr 作为数组?我现在就试试。感谢您的回复。 @KajolK 检查编辑以获取数组和指针之间的区别 在 C 中,数组索引只是添加后指针的取消引用:x[i] 仅表示 *(x + i) @KajolK;永远记住pointers are not arrays and vice-versa。 @KajolK:不,这意味着索引运算符[] 需要一个指针,而不是数组作为其操作数之一。通常,该指针是数组名称隐式转换的结果。【参考方案3】:

表达式status[10] 只是*(status+10) 的语法糖。

\0 终止用于在后台检查结束,如果您自己实现一些字符串处理程序,您也可以这样做,或者您可以忽略它并使用其他参数 size字符串,或者你可以(不要!)选择其他任何东西作为终止符号。

这不仅适用于 char 数组或“字符串”,C 数组只是指向类似类型内容的连续块的指针,并在编译时检查“数组”下标不存在t 超出声明时指定的“结束”。使用*(array+offset) 表示法,您需要自己检查。

【讨论】:

@MattMcNabb status[10] 在这里不是未定义的行为;该标准定义了取消引用过去数组的最后一个元素。 @BlacklightShining 它只定义是否保证在该位置分配内存(并且某些其他条件为真),char status[10]; 不是这种情况 status[10]*(status+10) 在任何地方except在问题所询问的特定上下文中的含义相同。【参考方案4】:

很高兴知道:

char status[10] = "Married";

只是 语法糖 的等价物:

char status[10]; // allocate 10 Bytes on stack
status[0] = 'M';
status[1] = 'a';
...
status[6]= 'd';
status[7] = '\0'; // same as 0

不多也不少。

还有:

char c = status[3];

一模一样

char c = *(status+3);

【讨论】:

除了new这里没有动态分配内存,所以应该是new (some address in .data or .rodata) char[10]; 我不确定,c 中是否有任何“新”关键字?还是我必须为此使用 C++? @KajolK:C 中现在有new。如果你想动态分配字符串,你需要malloc() 好吧,我做的 C# 太多了。编辑了我的答案。谢谢。 @che C 中没有 new。*(我花了很长时间寻找带有 new 关键字的 C 版本……)【参考方案5】:

字符串末尾的 '\0' 是一个无用的附加组件,旨在方便或安全。你可以像这样使用'sizeof'来告诉字符串的最后一个字符:

char status[] = "Married"; 

size_t szLastCharstatus = sizeof(status) / sizeof(status[0]) - 2;

char chLastChar = status[szLastCharstatus];

详细解释:

sizeof(status)

返回数组占用的字节数。

sizeof(status[0])

返回第一个元素占用的字节数(其余的也是如此)。

这两个值之间的除法为我们提供了数组中元素的数量。现在要访问最后一个元素,我们需要减去 2 次,因为数组中的元素从零开始计数,并且字符串中的最后一个字符是 '\0'。

还要注意数组不是指针,反之亦然。数组隐式转换为其第一个元素的指针、常量大小和它们自己的类型。它们可以通过指针或值传递(第二个需要使用结构破解)。

请注意,我使用的是“size_t”,它是存储一定大小数据的变量的类型定义。

【讨论】:

这将给出数组中元素的数量,而不是数组中包含的字符串的长度。由于仅初始化了 8 个字符,因此最后两个字符将具有不确定的值,读取它们将导致未定义的行为。另请注意,这仅适用于“正确”数组,一旦数组衰减到指针,sizeof 技巧将不再起作用。而且终止符也不是没用的,所有标准的 C 字符串函数都依赖于它的存在。 另请注意,问题标记为C,因此没有std 命名空间。 @Joachim Pileborg 然而,有时这会降低性能,避免它需要复杂的语法。只要数组通过值或指针传递,这个技巧就会起作用。也修复了“C”。 尾随的空字节根本没有用——因为指针衰减,它实际上是 only 找到字符串结尾的方法,如果它是例如作为参数传递给函数。【参考方案6】:

要获取索引 4 strPtr 处的字符,您只需使用 strPtr[4](这也适用于 status)。

要在使用strPtr 时获取字符串的结尾,您需要遍历字符并查找终止符\0。这就是printf("%s", strPtr) 在打印字符串时所做的(以及在解析"%s" 表达式时,这只是另一个字符串)。要在 C 中的字符串中查找多个有效字符,请使用 strlen() 函数。哦,确保你不要做这样的事情:

char a[3];
strcpy(a, "Hello!");

因为这会将 7 个字节写入 3 个字节的内存空间,因此会覆盖您不想覆盖的内容。

【讨论】:

以上是关于理解 char array[] 和 string的主要内容,如果未能解决你的问题,请参考以下文章

JAVA SE——对String类的深入理解

java char Array to string

Java 使用 char[] Array 还是 String 存储字符串密码

const char array (c style string) 模板特化

String对象的一些函数用法与心得

关于char*, char[], string的理解