为什么循环以这种方式工作?

时间:2017-01-03 14:29:47

标签: c string loops while-loop

我创建了一个程序。它起作用,因为我希望它起作用,但我不明白为什么。

这是功能。

void LiteraMajuscula(char *str)
{
    int i;

    i = 0;
    while (str[i] != '\0')
    {
        if (i == 0 && str[i] >= 'a' && str[i] <= 'z')
            str[i] -= 32;
        if (str[i-1] == ' ' && str[i] >= 'a' && str[i] <= 'z')
            str[i] -= 32;
        i++;
    }
}

每当有空格而且只有第一个字符并且字符串中的第一个字符是小写时,应该将小写字符变成大写字母,使其成为大写字母。

我唯一不理解的是str[i-1]。我尝试了str[i],但它没有改变任何内容,str[i-2]将第二个字母更改为大写而不是第一个字母。那是为什么?

3 个答案:

答案 0 :(得分:3)

str[i] -= 32;将转换索引i处的字符。第二个if语句在其检查中使用str[i-1] == ' '的原因是它知道当前字符(i)是否位于空格之后(i - 1)。当您将单词的第二个字符更改为str[i-2] == ' '时,它转换为单词的第二个字符的原因是您更改了它,以便它转换为字符(如果i空格后面的两个字符(i-2)。

如评论中所述,代码中存在未定义的行为,因为str[i-1] == ' ' i0检查str[i-1]时没有任何阻止,str将访问if所指向的字符

另外,由于大多数条件和逻辑在两个||之间重复,因此您可以使用while (str[i] != '\0') { if ((i == 0 || str[i-1] == ' ') && str[i] >= 'a' && str[i] <= 'z') str[i] -= 32; i++; } (逻辑OR):

()

(请注意||周围的||。)

i短路,所以当0str[i-1] == ' '并且第一个操作数为真时,第二个操作数("Pre Construction::Bid Date" ≥ "Bid Date Search::Start Date" & "Pre Construction::Bid Date" ≤ "Bid Date Search::Start Date" )永远不会被评估,因此您可以避免未定义行为。

答案 1 :(得分:0)

循环体不正确

while (str[i] != '\0')
{
    if (i == 0 && str[i] >= 'a' && str[i] <= 'z')
        str[i] -= 32;
    if (str[i-1] == ' ' && str[i] >= 'a' && str[i] <= 'z')
        str[i] -= 32;
    i++;
}

i等于tp 0时,则处于此状态

    if (str[i-1] == ' ' && str[i] >= 'a' && str[i] <= 'z')
        ^^^^^^^^

尝试访问字符串之外的内存。循环应至少重写为

while (str[i] != '\0')
{
    if ( ( i == 0 || str[i-1] == ' ' ) && str[i] >= 'a' && str[i] <= 'z')
        str[i] -= 32;
    i++;
}

这是条件检查字符串的第一个字符是否为字母字符,或者它是否不是字符串的第一个字符,前一个字符是否为空格而当前字符是字母字符。

考虑到该功能不适用于EBCDIC字符。最好使用标头toupper中声明的标准C函数<string.h>。例如

while (str[i] != '\0')
{
    if ( i == 0 || str[i-1] == ' ' )
    { 
        if (isalpha((unsigned char)s[i]) ) s[i] = toupper((unsigned char)s[i]);
    }
    i++;
}

我认为还需要检查前一个字符是否是制表符。此类字符串函数通常也会返回目标字符串。

我会按照以下方式编写函数

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

char * LiteraMajuscula( char *s )
{
    for (size_t i = 0; 
         s[i += strspn(s + i, " \t")] != '\0'; 
         i += strcspn( s + i, " \t" ))
    {
        if (isalpha((unsigned char)s[i]) ) s[i] = toupper((unsigned char)s[i]);
    }

    return s;
}

int main(void)
{
    char s[] = "hello,\tworld!";

    puts(s);
    puts(LiteraMajuscula(s));

    return 0;
}

它的输出是

hello,  world!
Hello,  World!

答案 2 :(得分:0)

发布的其他答案解释了代码的错误。

使用ctype.h中的函数,这是一种可以重写函数以提高效率和可移植性的另一种方法:

void do_some_incorrect_capitalization (char str[])
{
  if(*str == '\0')
  {
    return ;
  }

  *str = toupper(*str); // special case, first letter in the string
  str++;

  while(*str != '\0')
  {
    if(isspace(*(str-1)))
    {
      *str = toupper(*str);
    }
    str++;
  }    
}