0

我正在制作一个短程序,给我一个名字的首字母,所以如果名字是 john smith,它会给我 JS。

我写的代码是:

#include <stdio.h>
#include <string.h>
#include <ctype.h>

int main(void)
{ 
    string name = "String Name Goes here"

    for (int i = 0, n = strlen(name); i < n; i++)
    {
        printf("%c", toupper(name[i]));
        while(name[i] != ' ')
        {
            i++;
        } 
    }
    printf("\n");
}

所以因为我只是使用了一个通用的字符串名称,所以我应该得到的结果是 SNGH。问题是,代码有时可以工作,有时我会遇到分段错误。它总是在字符串中有大写字母时出现,但是当字符串中没有大写字母时,有时它会输出我想要的。我知道这与访问我不允许访问的内存有关,但我不明白这在这里如何应用,因为我只访问 i 计数器。

为什么会发生这种情况?

*编辑:我使用'string'的原因是因为我正在访问一个不同的库,我没有在此处列出它定义了一个获取字符串的函数。所以我可以得到字符串,我只是用我之前的代码替换了代码。那不是导致问题的部分。

4

2 回答 2

5

正如评论中已经提到的,如果您正在处理的字符串不以空格字符结尾,则此循环将跳过字符串终止符并在name变量之外的内存中查找空格字符。如果它在到达太远之前找到一个空格字符,则程序成功终止。如果它最终没有找到空间,您会因为尝试从无效的内存位置读取而收到“分段错误”错误。

    while(name[i] != ' ')
    {
        i++;
    } 

除了空格之外,修复程序还检查字符串终止符:

    while(name[i] != ' ' && name[i] != '\0')
    {
        i++;
    }

当然,这是假设string这里实际上是一个 C 字符串:char[]char*

例如,您可以通过在valgrind. 您将得到的输出告诉您第while12 行的 -statement 使用了未初始化的内存:

==9110== Conditional jump or move depends on uninitialised value(s)
==9110==    at 0x4006B1: main (test.c:12)
于 2013-09-25T09:46:54.727 回答
2

首先,您使用的是 C++ 头文件。你只需要<stdio.h>你的程序。

C中没有确定的类型string(即使您可以定义一个)。字符串可以存储在诸如char数组之类的东西中,因此您的变量声明应如下所示:

char* name = "String Name Goes here";

如果您确实string在另一个库中定义的类型,那么获取其长度和其他属性的唯一正确方法是使用库提供的函数。您不能拥有自定义字符串类型并假设它以空值结尾(这就是strlen其他人所假设的)。

如果是(假设是 C-like char[],即),则以下

while(name[i] != ' ')
{
    i++;
}

将始终超出范围,除非源文本确实以空格结尾。它最终可能会停在一个垃圾空白处(如果你不走运的话)或导致分段错误(如果你走运的话)。在任何情况下,它都会尝试访问它应该访问的内存(正如您在问题中正确猜到的那样)并且它调用了我们所说的未定义行为

于 2013-09-25T09:48:16.633 回答