Question

I have to basically take the input array of characters and translate it into the result array using rot-13. So, here's what I'm thinking of doing: use a for loop and then use conditionals inside the for loop to determine whether or not to add or subtract 13 places. But what I'm having trouble with is writing the for loop.

Here's the function that I have to implement:

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

I know that when you write a for loop, it looks something like this:

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

So I have written my test cases, but the compiler won't compile.

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

I'm not sure what I did wrong and the compiler complains about line 9. I'm thinking it has something to do with the way I wrote "checkit_string...", but I'm not too sure.

Was it helpful?

Solution 3

Here is a nice simple example of looping over a string in 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));
}

Look at just the for loop. There are three parts: initialization, test, and the step. Then there is either a single statement, or else a "block" (a set of zero or more statements enclosed in curly braces). In my example, the block is empty (other than a human-readable comment that doesn't execute).

The initialization is executed once and should be used to set up the loop somehow; in my example, it's used to set i to zero. The "test" is some expression that is evaluated before the loop body is executed; if the test evaluates false, the loop terminates, so a condition that is false before the loop even does anything will cause the loop body to never be executed. If the test evaluates true, the loop body is executed, and after that the "step" is executed; the "step" should advance the loop somehow. In my example, the test is checking to see whether the loop has found the terminating NUL byte yet, and the step increments the loop counter i.

So think about how this loop works. We start i at zero, then the loop immediately checks to see if the first character in the string is a NUL byte. If it is, the loop is already over, and our length() function returns 0, which is correct! If the first byte of a string is a terminating NUL byte, then that is a "null string" and the correct length is 0. (It's important when writing loops to think about what happens if the loop does nothing. Loops should "do nothing" correctly; this one does.)

An interesting thing about C's for loop: all the parts of the loop are optional. Here are some alternate versions of the loop; these will all work.

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

In this example, we initialize i outside the loop, and the initialization part is left empty. The empty statement with a single semicolon is unusual but legal. More often, you will see someone put something like this: NULL; The NULL is evaluated, but then the value isn't saved anywhere, so this is also a do-nothing statement.

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

In this example, after the test, the loop body is run; this increments i. Then the "step" part of the loop is omitted.

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

In this example, all three parts of the for loop are omitted, which is legal and basically means "loop forever until something stops the loop". Then in the if statement, if we see the NUL byte we execute the break statement, which terminates the loop. Finally we increment i.

Note that the initialization, test, and step are actually present; they just aren't in the for loop line. For simple loops like this one, I recommend the standard form, not this weird form.

Finally, some people will write a tricky loop that increments the character pointer itself, rather than incrementing a loop variable like i. Here's an example:

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

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

    return (s - start);
}

In this example, we increment the variable s itself. Since it was passed as an argument, the function has its own copy and it can modify that copy without affecting anything else outside the function. This saves a copy of the initial pointer, increments until the terminating NUL is found, then subtracts the start position from the new position to find the length.

Usually people will shorten the loop. The test is true if the test expression is non-zero, and in a string, only the NUL byte is zero. So the test expression can simply be *s and it will evaluate true if the current position is not a NUL byte:

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

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

    return (s - start);
}

And finally, we could make this a bit shorter with a while loop:

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

    while (*s)
        ++s;

    return (s - start);
}

It's short and terse, but it's pretty clear once you are used to this stuff.

OTHER TIPS

size = strlen(input), assuming input is a NUL terminated string, ie. simply loop until input[i] == '\0'. Since input is a char*, you can just increment it until *input == '\0'.

If it's not a NUL terminated string, then you must provide the size to str_rot_13, otherwise you can't tell the length of the array when it's passed to the function (as it decays to a pointer).

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;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top