理解char array[]和string

16

我是编程新手。 我的第一个编程语言是C语言。 我发现有些东西很难理解。

我学到了在C语言中我们可以使用字符数组来表示字符串,如下:

char status[10] = "Married";   

我已经了解到这种方法的问题在于编译时必须告知status数组的大小。

但现在我已经学习到可以使用char指针表示类似于string的字符串,如:

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

我没有很好地理解它。我的问题是 -

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

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


2
  1. *(strPtr+4)会给你字符i
  2. strPtr也指向status,所以它在末尾也有(相同的)空字符(\0)。
- P.P
2
因为数组会衰变成指向它们第一个元素的指针,所以数组和指针经常可以互换使用,因此在数组上使用解引用运算符将起作用,使用指针上的数组索引运算符也是如此。另外,*(arrayOrPointer + X) 等同于 arrayOrPointer[X] - Some programmer dude
检查sizeof(&array)返回什么? - Grijesh Chauhan
6个回答

15
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++是不允许的,因为数组不是可修改的左值(lvalue)


哇!这意味着我们可以将指针名称“strPtr”用作数组?我现在会尝试一下。谢谢你的回复。 - KajolK
@KajolK 请检查编辑内容,了解数组和指针之间的区别。 - Gopi
在 C 语言中,数组索引只是指针加上偏移量后的解引用操作:x[i] 的实际意义就是 *(x + i) - Mark Cidade
1
@KajolK;永远记住指针不是数组,反之亦然 - haccks
@KajolK:不,这意味着索引运算符[]需要一个指针而不是数组作为其操作数之一。通常,该指针将是数组名称的隐式转换的结果。 - Keith Thompson

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];

“exactly”和“完全相同”是一样的意思。

char c = *(status+3);

除了这里的 new 不会动态分配内存,所以应该是 new (在 .data 或 .rodata 中的某个地址) char[10]; - myaut
1
我不确定C语言中是否有"new"关键字?还是我必须使用C++? - KajolK
@KajolK:现在C语言中有new了。如果你想动态分配字符串,你需要使用malloc()函数。 - che
我做了太多的C#。编辑了我的回答。谢谢。 - DrKoch
@Matt 确实,我改变了我的答案。谢谢。 - DrKoch
1
@che C语言中没有new关键字。*(我花了太长时间寻找带有new关键字的C语言版本...) - Blacklight Shining

4
表达式status[10]只是*(status+10)的语法糖。
在底层,\0终止符被用于检查结尾。如果您要自己实现一些字符串处理程序,也可以这样做,或者您可以忽略它并使用字符串给定的其他参数size,或者(不建议!)选择其他内容作为终止符号。
这不仅适用于char数组或“字符串”,C数组只是指向同类型连续块的指针,并且在声明时进行编译时检查以确保您的“数组”下标不会超过“结束”。对于*(array+offset)符号,需要自行检查此问题。

@MattMcNabb 这里并不是未定义的行为 status[10];标准定义了可以对数组的最后一个元素地址向后访问。 - Blacklight Shining
@BlacklightShining 它只是定义了如果在该位置保证分配了内存(并且满足其他一些条件),而 char status[10]; 不符合这种情况。 - M.M
status[10] 在任何情况下都与 *(status+10) 意思相同,除了问题所询问的特定上下文。 - user1084944

3
我要提出一个挑战性的观点:可以这样认为,C 没有字符串。 C 只有 char 数组。而且尽管它的名字是“字符型”,但实际上 char 是一种数值类型(例如,'A' 通常表示数字 65)。 char 数组与其他数值类型的数组并没有本质区别;只是编程语言提供了一些额外的方式来编写 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";

3
要在索引4处获取字符 strPtr ,只需使用 strPtr [4] (这对 status 也适用)。
当使用 strPtr 时,要获取字符串的结尾,需要遍历字符并查找终止符号 \ 0 。这就是在打印字符串时 printf(“%s”,strPtr)所做的事情(也是解析“%s”表达式时所做的事情,它只是另一个字符串)。要在C中查找字符串中有效字符的数量,可以使用 strlen()函数。哦,还要确保不要做这样的事情:
char a[3];
strcpy(a, "Hello!");

由于这将在三个字节的内存空间中写入7个字节,因此会覆盖您不想被覆盖的内容。


1
字符串末尾的'\0'是为了方便或安全而添加的无用字符。您可以使用'sizeof'来判断字符串的最后一个字符,如下所示:
char status[] = "Married"; 

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

char chLastChar = status[szLastCharstatus];

详细解释:
sizeof(status)

返回数组占用的字节数。
sizeof(status[0])

返回第一个元素占用的字节数(以及其余元素)。这两个值之间的除法给出了数组中元素的数量。现在,要访问最后一个元素,我们需要将其减去两次,因为数组中的元素从零开始计数,并且字符串中的最后一个字符是'\0'。此外,请注意数组不是指针,反之亦然。数组具有对其第一个元素的指针的隐式转换、常量大小和自己的类型。它们可以通过指针或值传递(对于第二种情况,需要使用结构体hack)。请注意,我正在使用 'size_t',这是存储某些数据大小的变量的类型定义。

1
这将给出数组中元素的数量,但不是数组中包含的字符串的长度。由于只初始化了8个字符,最后两个字符将具有不确定的值,并且读取它们将导致未定义的行为。还要注意,这仅适用于“正确”的数组,一旦数组已经衰变为指针,sizeof技巧将不再起作用。终止字符并不是无用的,所有标准的C字符串函数都依赖于它的存在。 - Some programmer dude
1
还要注意问题标记为 C,因此没有 std 命名空间。 - Some programmer dude
@Joachim Pileborg,然而有时候这会带来性能成本,避免它需要复杂的语法。只要数组通过值或指针传递,这个技巧就可以起作用。同时也适用于'C'。 - AnArrayOfFunctions
1
结尾的空字节一点也不无用——由于指针衰减,如果将其作为参数传递给函数,它实际上是找到字符串结尾的唯一方法。 - Blacklight Shining

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接