tags:

views:

222

answers:

6

i have to char[] in C and i wanted to swap between them, by only swaping the pointer to the array and not one char at a time so i wrote this code:

#include <stdio.h>
void fastSwap (char **i, char **d)
{
    char *t = *d;
    *d = *i;
    *i = t;
}
int main ()
{
    char num1[] = "012345678910";
    char num2[] = "abcdefghujk";
    fastSwap ((char**)&num1,(char**)&num2);
    printf ("%s\n",num1);
    printf ("%s\n",num2);
    return 0;
}

I get this output (note the last 4 characters)

abcdefgh8910
01234567ujk

When I expect:

abcdefghujk
012345678910

NOTE: I am working on a 64 bit Linux System.

A: 

Change fastSwap to:

void fastSwap (char *i, char *d)
{
   while ((*i) && (*d))
   {
      char t = *d;
      *d = *i;
      *i = t;

      i ++;
      d ++;
   }
}

then call fastSwap (num1, num2);

florin
...and rename it to `slowSwap()`.
sbi
+6  A: 

Arrays are not pointers. While they decay to pointers when you call your fastSwap(), these pointers are not the actual arrays. The fact that you need a cast should give you a hint that something is wrong.

This would work:

void fastSwap (const char **i, const char **d)
{
    const char *t = *d;
    *d = *i;
    *i = t;
}

const char* num1 = "012345678910";
const char* num2 = "abcdefghujk";
fastSwap (&num1,&num2);
printf ("%s\n",num1);
printf ("%s\n",num2);
sbi
@sbi: have you actually compiled and ran it?
florin
@florin: Yes. Why?
sbi
I would have expected an error on the const-ness of your pointers.
Mark Ransom
There should at least be a warning, for passing `const char **` values to a function expecting `char **`.
caf
@florin, @Mark, @caf: You're right! I had to change the `fastSwap()` function as well, but forgot about that! Added it now.
sbi
+8  A: 

You can't modify the addresses of num1 and num2, your code should work if your test was instead:

int main ()
{
    char num1[] = "012345678910";
    char num2[] = "abcdefghujk";
    char *test1 = num1;
    char *test2 = num2;
    fastSwap (&test1,&test2);
    printf ("%s\n",test1);
    printf ("%s\n",test2);
    return 0;
}
Mark E
Look again at his output. I was fooled, too.
sbi
MerickOWA
hey Merick, can you please explain more about what you think the problem is.
bass
MerickOWA
@bass: __(1)__ You need to turn your...thing into a real question. Seeing that the code does indeed swap, I wonder what you are asking. __(2)__ When replying to a comment, you need to properly @address people. As it is, Merick would never see you asked him, unless he comes back here and looks. __(3)__ If Merick is right (and I believe he is), you're invoking _Undefined Behavior_. So that your code actually swaps is by accident. It might just as well format your HD. Make the arrays longer and it will behave funny.
sbi
@MerickOWA: I figured it's invoking UB, but I had no idea why this was appearing to work. Your explanation makes sense, though. Turn it into an answer and be up-voted.
sbi
@sbi it only appears to partially "work" -- that is, the last 4 characters don't actually get "swapped". My solution holds as valid, and I believe I'm correct in saying that @bass "can't" really modify the `num1` and `num2`.
Mark E
@Mark: Yes, the original code only worked by accident (and might not work at all, when using a different compiler, or compiler version, or day of the week). And, yes, your code actually works. However, your question doesn't address the problem in the original code. Instead it just presents another solution which produces the same result. Which is why I didn't up-vote your answer.
sbi
@sbi: I understand that the original is UB, but my solution produces a very different result: http://ideone.com/llMvI
Mark E
@Mark: Yeah, I see it now. Sorry for misreading. Up-voted.
sbi
This answer would be much more useful if it went into why the original code didn't work, rather than just presenting fixed code. This is how cargo cults get started.
Mark Ransom
+5  A: 

This will work:

int main ()
{
    char *num1 = "012345678910";
    char *num2 = "abcdefghujk";
    fastSwap (&num1,&num2);
    printf ("%s\n",num1);
    printf ("%s\n",num2);
    return 0;
}
Karl Bielefeldt
+3  A: 

Your fastSwap only seems to work. You're invoking undefined behavior by casting '&num1' and '&num2' (which are pointers to the characters of num1 and num2) to pointers to pointers of characters (char**).

char *t = *d

t will point to whatever d's contents are pointing to, however d is pointing to the actually characters of num2 ("abcdefghujk" or 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x75 0x6B 0x00). This means that '*d' is actually copying the contents of 'num2' and not the pointer to num2 as you probably expected.

't' then is a bad pointer however since it is never dereferenced you avoid a crash/segment fault.

Because you're on a 64 bit machine/OS pointers are 8 bytes the value of 't' is now the first 8 bytes of 'num2' and this is what gets put into num1 after

*i = t

If you intend to swap pointers you must first create pointer variables as Mark did

char *test1 = num1;
char *test2 = num2;
fastSwap (&test1,&test2);

Or change num1 and num2 into pointers (char *) rather than arrays (char[]) as sb1/Karl did

char *num1 = "012345678910";
char *num2 = "abcdefghujk";
fastSwap (&num1,&num2);
MerickOWA
+4  A: 

num1 is an array, and &num1 is the address of the array itself - it is not an address of a pointer.

The address of an array itself is the same location in memory as the address of the first element of the array, but it has a different type. When you cast that address to char **, you are claiming that it points at a char * value - but it does not. It points at a block of 13 chars. Your swap function then accesses that array of 13 chars as if it were a char * - since the latter is the same size as 8 chars on your platform, you end up swapping the first 8 chars of each array.

caf