tags:

views:

307

answers:

4

C function to rotate a string by a given number to the right or to the left. When a character is rotated past the end or the beginning of a string depending on the direction, it should wrap around

+7  A: 

given a string str which has length length and a rotation amount n

rotate left is equivalent to

reverse(str, 0, n);
reverse(str, n, length);
reverse(str, 0, length);

rotate right is equivalent to

reverse(str, 0, length - n);
reverse(str, length - n, length);
reverse(str, 0, length);

Now you just need a reverse function.

Update: I thought of how you can use mod's to make you always rotate in the right direction depending on the sign of n.

e.g.

int mod = n % length;
if (mod != 0) { //if 0, don't rotate
    reverse(str, 0, mod);
    reverse(str, mod, length);
    reverse(str, 0, length);
}

going through the various cases

if n == 5 and length = 10, mod = 5

if n == 16 and length = 10, mod = 6 -- rotating left by 16 = rotating left by 6

if n == 0 and length = anything, mod = 0

if n == -1 and length = 10, mod = 9 -- rotating right by 1 is the same as rotating left by 9

if n == -15 and length = 9, mod = 3 -- rotating right by 15 is the same as rotating left by 3

barkmadley
And now you have two problems (or more correctly, a different problem).
paxdiablo
+1: Reminds me of the hand-flipping explanation in Jon Bentley's 'Programming Pearls' (or 'More Programming Pearls').
Jonathan Leffler
@paxdiablo: even more correctly, an *easier* problem. And likely a previously-solved one, since "reversing a string" probably comes before "rotating a string" in the Big Introductory Book of String Manipulation ;-)
Steve Jessop
@Jonathan - that's awesome. I've not read that book, don't remember ever hearing any such explanation, but just the words "hand flipping" was enough for me to see how to physically demonstrate that this technique is correct. Then it took me three attempts to do it without running out of rotation on my elbows (hint: flip both hand in the *same* direction), but nothing's ever *completely* trivial...
Steve Jessop
+2  A: 

I'd do something like this:

void rot(char *buf, int len, int r)
{
  char *temp=malloc(r>=0?r:-r);
  if(r>=0)
  {
    memcpy(temp, buf+len-r, r);
    memmove(buf+r, buf, len-r);
    memcpy(buf, temp, r);
  }
  else
  {
    memcpy(temp, buf, r);
    memmove(buf, buf+r, len-r);
    memcpy(buf+len-r, temp, r);
  }

  free(temp);
}

provided of course that r<len, len is at least 1, you know, normal sanitation checks.

Blindy
The second `memcpy()` in each block should be `memmove()` for correctness.
Chris Lutz
couldn't remember which was the safe one to handle overlapping buffers, thanks.
Blindy
A: 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

char* strrot (int offset, size_t size, const char *inStr);

int main (int argc, const char * argv[]) {
    const char *rotStr = "rotateme";
    size_t rotStrSize = strlen(rotStr);
    char *resultStr;

    resultStr = strrot(-3, rotStrSize, rotStr);
    printf("-3, %s\n", resultStr);
    free(resultStr);

    resultStr = strrot(2, rotStrSize, rotStr);
    printf("+2, %s\n", resultStr);
    free(resultStr);

    resultStr = strrot(11, rotStrSize, rotStr);
    printf("+11, %s\n", resultStr);
    free(resultStr);

    resultStr = strrot(0, rotStrSize, rotStr);
    printf("0, %s\n", resultStr);
    free(resultStr);

    resultStr = strrot(-11, rotStrSize, rotStr);
    printf("-11, %s\n", resultStr);
    free(resultStr);

    return 0;
}

char* strrot (int offset, size_t size, const char *inStr) {
    char *result = (char *)malloc(size * sizeof(char));
    int trueOffset = size - (offset % size);

    int inIndex = trueOffset;
    int outIndex = 0;

    for (inIndex = trueOffset; inIndex < (int)size; inIndex++, outIndex++) {
        result[outIndex] = inStr[inIndex];
    }
    for (inIndex = 0; inIndex < trueOffset; inIndex++, outIndex++) {
        result[outIndex] = inStr[inIndex];
    }

    result[(int)size] = '\0';

    return result;
}

Results:

-3, atemerot
+2, merotate
+11, emerotat
0, rotateme
-11, atemerot
Alex Reynolds