1

我必须基本上采用输入字符数组并使用 rot-13 将其转换为结果数组。所以,这就是我想做的事情:使用 for 循环,然后在 for 循环中使用条件来确定是否添加或减去 13 个位置。但我遇到的问题是编写 for 循环。

这是我必须实现的功能:

    void str_rot_13(char const input[], char result []);

我知道当你编写一个 for 循环时,它看起来像这样:

    for (int i = 0; i < size; i++)

所以我写了我的测试用例,但是编译器不会编译。

#include "string.h"
#include "checkit.h"

void str_rot_13_tests(void)
{
   char input[3] = {'a', 'C', 'd'};
   char result[3] = {'n', 'P', 'q'};

   checkit_string(str_rot_13("aCd", 3), "nPq")
}

int main()
{
   str_rot_13_tests();

   return 0;
}

我不确定我做错了什么,编译器抱怨第 9 行。我认为这与我编写“checkit_string ...”的方式有关,但我不太确定。

4

3 回答 3

1
char char_rot_13(char c){
   char new_c = c;

   if (c >= 'a' && c <= 'z')
   {
      new_c = c + 13;
      if(new_c > 'z')
          new_c -= 26;
   }
   else if (c >= 'A' && c <= 'Z')
   {
      new_c = c + 13;
      if(new_c > 'Z')
          new_c -= 26;
   }
   return new_c;
}
void str_rot_13(char const input[], char result []){
    while(*input){
        *result++ = char_rot_13(*input++);
    }
    *result ='\0';
}

测试:

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

char *str_rot_13(char const input[], char result[]){
    char *p=result;
    while(*input){
        *p++ = char_rot_13(*input++);
    }
    *p ='\0';
    return result;
}
int main (void){
    char result[128];
    assert(strcmp(str_rot_13("acd", result), "npq")==0);
    printf("%s", result);

  return 0;
}
于 2013-05-16T01:01:09.637 回答
1

size = strlen(input),假设input是一个以 NUL 结尾的字符串,即。只需循环直到input[i] == '\0'. 由于input是 a char*,因此您可以将其递增直到*input == '\0'

如果它不是以 NUL 结尾的字符串,那么您必须将大小提供给str_rot_13,否则当数组传递给函数时,您无法知道数组的长度(因为它会衰减为指针)。

于 2013-05-16T00:59:49.450 回答
0

这是在 C 中循环字符串的一个很好的简单示例。

#include <stdio.h>

int length(char const *s)
{
    int i;

    for (i = 0; s[i] != '\0'; ++i)
    {
        /* loop body is empty */
    }

    return i;
}

int main(int argc, char *argv[])
{
    char const test[] = "hello";

    printf("String: '%s'  length: %d\n", test, length(test));
}

只看for循环。分为三个部分:初始化、测试和步骤。然后有一个语句,或者一个“块”(一组零个或多个用花括号括起来的语句)。在我的示例中,该块是空的(除了不执行的人类可读注释)。

初始化执行一次,应该用于以某种方式设置循环;在我的示例中,它用于设置i为零。“测试”是在循环体执行之前评估的一些表达式;如果测试结果为假,则循环终止,因此在循环执行任何操作之前为假的条件将导致循环体永远不会被执行。如果测试结果为真,则执行循环体,然后执行“步骤”;“步骤”应该以某种方式推进循环。在我的示例中,测试正在检查循环是否已找到终止 NUL 字节,并且该步骤会增加循环计数器i

所以想想这个循环是如何工作的。我们i从零开始,然后循环立即检查字符串中的第一个字符是否为 NUL 字节。如果是,则循环已经结束,我们的length()函数返回 0,这是正确的!如果字符串的第一个字节是终止 NUL 字节,那么这是一个“空字符串”并且正确的长度为 0。(在编写循环时考虑如果循环什么都不做会发生什么是很重要的。循环应该“什么都不做" 正确;这个可以。)

关于 C 循环的一个有趣的事情是for:循环的所有部分都是可选的。以下是循环的一些替代版本;这些都会起作用。

i = 0;  /* initialize i before loop */
for (; s[i] != '\0'; ++i)
    ;  /* looks weird but this is a statement that does nothing */

在这个例子中,我们i在循环外进行初始化,初始化部分留空。带有单个分号的空语句不常见但合法。更多的时候,你会看到有人这样写: NULL; TheNULL被求值,但是值没有被保存到任何地方,所以这也是一个无所事事的声明。

for (i = 0; s[i] != '\0';)
{
    ++i;  /* do the step part as the loop body */
}

在这个例子中,在测试之后,循环体被运行;这增加了i。然后省略循环的“步骤”部分。

i = 0;  /* initialization */
for (;;)
{
    if (s[i] == '\0')  /* test */
        break;
    ++i;  /* step */
}

在这个例子中,循环的所有三个部分for都被省略了,这是合法的,基本上意味着“永远循环,直到有东西停止循环”。然后在if语句中,如果我们看到 NUL 字节,我们将执行该break语句,从而终止循环。最后我们增加i.

请注意,初始化、测试和步骤实际上是存在的;他们只是不在for循环线中。对于像这样的简单循环,我推荐标准形式,而不是这种奇怪的形式。

最后,有些人会编写一个棘手的循环来递增字符指针本身,而不是像i. 这是一个例子:

int length(char const *s)
{
    char const *start;

    for (start = s; *s != '\0'; ++s)
    {
    }

    return (s - start);
}

在这个例子中,我们增加了变量s本身。由于它是作为参数传递的,因此该函数有自己的副本,它可以修改该副本而不影响函数之外的任何其他内容。这保存了初始指针的副本,递增直到找到终止 NUL,然后从新位置减去起始位置以找到长度。

通常人们会缩短循环。如果测试表达式不为零,则测试为真,并且在字符串中,只有 NUL 字节为零。所以测试表达式可以很简单*s,如果当前位置不是 NUL 字节,它将评估为真:

int length(char const *s)
{
    char const *start;

    for (start = s; *s; ++s)
    {
    }

    return (s - start);
}

while最后,我们可以通过循环使它更短一些:

int length(char const *s)
{
    char const *start = s;

    while (*s)
        ++s;

    return (s - start);
}

它简短而简洁,但是一旦您习惯了这些东西,就会很清楚。

于 2013-05-16T04:28:22.737 回答