如何迭代C中的字符串?

Vin*_*ent 48 c iteration

现在我正在尝试这个:

#include <stdio.h>

int main(int argc, char *argv[]) {

    if (argc != 3) {

        printf("Usage: %s %s sourcecode input", argv[0], argv[1]);
    }
    else {
        char source[] = "This is an example.";
        int i;

        for (i = 0; i < sizeof(source); i++) {

            printf("%c", source[i]);
        }
    }

    getchar();

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这也不起作用:

char *source = "This is an example.";
int i;

for (i = 0; i < strlen(source); i++){

    printf("%c", source[i]);
}
Run Code Online (Sandbox Code Playgroud)

我收到了错误

Test.exe中0x5bf714cf(msvcr100d.dll)的未处理异常:0xC0000005:读取位置0x00000054时发生访问冲突.

(从德语松散翻译)

那我的代码出了什么问题?

小智 55

你要:

for (i = 0; i < strlen(source); i++){
Run Code Online (Sandbox Code Playgroud)

sizeof给出指针的大小,而不是字符串.但是,如果您将指针声明为数组,它将起作用:

char source[] = "This is an example.";
Run Code Online (Sandbox Code Playgroud)

但是如果你将数组传递给函数,它也会衰减到指针.对于字符串,最好始终使用strlen.并注意其他人已经说过如何更改printf以使用%c.而且,考虑到mmyers对效率的评论,最好将调用移出strlen:

int len = strlen( source );
for (i = 0; i < len; i++){
Run Code Online (Sandbox Code Playgroud)

或重写循环:

for (i = 0; source[i] != 0; i++){
Run Code Online (Sandbox Code Playgroud)

  • 好吧,最后我检查过,strlen不得不遍历所有字符来计算长度.并且由于char*可能在循环中发生变化,因此编译器无法将strlen提升出边界检查; 这使得循环O(n ^ 2)而不是O(n).如果我错了,请纠正我. (11认同)
  • 呃,我有点怀疑他想用`strlen`作为界限.(尽管在10行计划中获得批准,但它没有太大区别.) (2认同)
  • @Neil Butterworth:for(i = 0,max = strlen(str); i <max; i ++)...和for(i = 0; i <strlen(str); i ++)...之间的差异是... O(n ^ 2)和O(n)之间的差异(除非你已经将它声明为const char*str),因为需要为每一轮循环计算上限. (2认同)

Ale*_* C. 41

一个常见的习语是:

char* c = source;
while (*c) putchar(*c++);
Run Code Online (Sandbox Code Playgroud)

几点说明:

  • 在C中,字符串以空值终止.在读取字符不是空字符时进行迭代.
  • *c++递增c并返回取消引用的c.
  • printf("%s")打印以null结尾的字符串,而不是char.这是您违反访问权限的原因.

  • 我可以使用`while (*c++) putc(*c);`吗? (3认同)
  • @Celeritas:我发现downvote有点苛刻 - C语言支持零终止字符串,而OP正在使用它们.当然,你可以使用计数字符串(例如,windows世界中的`BSTR`),但是它们不太常见,并且关于使用哪种字符串类型的问题并不明确. (3认同)
  • 哦,你刚才在谈论他们是如何被召集的?零终止是来自Win32 API世界的名称(其中字符串变量以`sz`为前缀愚蠢),而null终止是更"传统"(和常见)名称.无论如何,它们都意味着相同. (3认同)
  • 这是来自`&lt;stdio.h&gt;`的[`putc`](https://en.wikibooks.org/wiki/C_Programming/stdio.h/putc)吗?因为该函数似乎需要第二个参数,即流。[`putchar`](https://en.wikibooks.org/wiki/C_Programming/stdio.h/putchar) 可以像这个例子那样只使用一个参数。 (2认同)

小智 8

一种优化方法:

for (char character = *string; character != '\0'; character = *++string)
{
    putchar(character); // Do something with character.
}
Run Code Online (Sandbox Code Playgroud)

大多数 C 字符串都是以 null 终止的,这意味着一旦字符变成 a,'\0'循环就应该停止。将*++string指针移动一个字节,然后取消引用它,然后重复循环。

之所以比它更有效,strlen()是因为 strlen 已经循环遍历字符串来查找长度,因此您实际上可以使用 . 循环两次(比需要的多一次)strlen()


Mar*_*ram 5

您可以只检查 NULL 字符,而不是像上面建议的那样使用 strlen:

#include <stdio.h>

int main(int argc, char *argv[])
{
    const char *const pszSource = "This is an example.";
    const char *pszChar = pszSource;

    while (pszChar != NULL && *pszChar != '\0')
    {
        printf("%s", *pszChar);
        ++pszChar;
    }

    getchar();

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

  • 它会起作用,但我建议检查 `pszChar != '\0'` 无论如何都是明确的。您不是与“NULL”(通常针对指针)进行比较,而是与终止 C 字符串的空字符进行比较。(或者,这两个值都等于 0,所以 `pszChar &amp;&amp; *pszChar` 也是一个很好的条件,如果您遇到这种情况的话)。 (2认同)