String Manipulation and rot-13

时间:2013-05-16 00:54:05

标签: c string for-loop rot13

我必须基本上使用输入的字符数组并使用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 ...”的方式有关,但我不太确定。

3 个答案:

答案 0 :(得分:1)

size = strlen(input),假设input是NUL终止字符串,即。只需循环直到input[i] == '\0'。由于inputchar*,因此您可以将其递增至*input == '\0'

如果它不是NUL终止的字符串,那么你必须提供str_rot_13的大小,否则当它传递给函数时(因为它衰减到指针)你无法分辨数组的长度。

答案 1 :(得分: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';
}

TEST:

#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;
}

答案 2 :(得分: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设置为零。 “test”是在循环体执行之前计算的一些表达式;如果测试评估为false,则循环终止,因此在循环之前做错的条件甚至会做任何事情将导致循环体永远不会被执行。如果测试评估为真,则执行循环体,然后执行“步骤”; “步骤”应以某种方式推进循环。在我的示例中,测试是检查循环是否已找到终止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; NULL被评估,但是值不会被保存在任何地方,所以这也是一个无用语句。

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);
}

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