0

I am trying to swap characters within a string that is a char *. I want the swap function to take in a void *[] to be generic, but I am getting an odd behavior and I am not sure why.

My main:

int main(int argc, char *argv[])
{
    size_t n_bytes = 100;
    int bytes;
    char *my_input;
    int numeric = 0;

    my_input = (char *) malloc(n_bytes + 1);

    /* if -n option is set, sort numerically versus lexicographically. */
    if (argc > 1 && strcmp(argv[1], "-n") == 0) numeric = 1;
    while(getline(&my_input, &n_bytes, stdin) && strlen(my_input) > 1)
    {
        swap((void **) my_input, 0, 2);
    }

    free(my_input);
    return 0;
}

swap function with printf-ing for "debugging":

void swap(void *v[], int i, int j)
{
    void *temp;
    printf("i: %d j: %d\n", i, j);
    for(int x = 0; x < strlen(v); x++)
    {
        printf("%c\n", v[x]);
    }
    temp = v[i];
    v[i] = v[j];
    v[j] = temp;
    printf("first letter: %c", v[j]);
}

What appears from the loop of printing is the first character of the string the user inputs (Ex. if input == "hello", the first character printed will be 'h'). The rest that is printed is always garbage though instead of the rest of the characters. The printf that prints what is held in v[j] prints out the swapped value which would be whatever the first character was. I am guessing I am missing a blatant concept, but can't seem to figure it out.

nalzok
  • 14,965
  • 21
  • 72
  • 139
httpNick
  • 2,524
  • 1
  • 22
  • 34
  • 1
    1. passing data having incorrect types to `printf` causes *undefined behavior*. `%c` accepts `int`, not `void*`. 2. using `strlen()` in loop condition may lead to bad performance. – MikeCAT Feb 21 '16 at 01:35
  • 1
    I guess you should imitate the prototype of [`qsort()`](http://linux.die.net/man/3/qsort). – MikeCAT Feb 21 '16 at 01:37
  • 2
    Different types use different amounts of memory. Unless I'm missing something, how do you expect the swap function to know how to swap things of unknown size -just using `void *`? – code_dredd Feb 21 '16 at 01:38
  • 2
    They say [you shouldn't cast the result of `malloc()` in C](http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc). – MikeCAT Feb 21 '16 at 01:40
  • 2
    `void *` is a generic pointer, but `void **` isn't. – nalzok Feb 21 '16 at 01:44
  • 2
    Compile with warnings on. – Paul Hankin Feb 21 '16 at 02:12
  • `strlen(v)` is an error, your compiler should tell you this. Pay attention to what your compiler says. I suspect you meant the function to take `void *`, not `void *[]` . – M.M Feb 21 '16 at 03:35

2 Answers2

0

You have defined a single dimension char array or char * and you are trying to convert to vaid*[], it is a 2 dimension array. Replacing void*[] with char* and void *temp with char temp should work in your program. (void *) is used to pass generic pointer type and you have to convert back to original type before accessing the pointer. Also just pass the input string as is replace the (void **) conversion.

Umamahesh P
  • 1,224
  • 10
  • 14
0

Your are processing an "array of char", rather than an "array of pointer to char", right?

void swapChar(char *v, size_t i, size_t j)
{
    char temp;
    printf("i: %zu j: %zu\n", i, j);
    int x;
    for(x = 0; x < strlen(v); x++)
    {
        printf("%c\n", v[x]));
    }
    temp = v[i];
    v[i] = v[j];
    v[j] = temp;
    printf("first letter: %c\n", v[j]));
}

If you want to make it generic, you have to tell it the size of elements:

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

void swap(char *v, size_t i, size_t j, size_t size)
{
    char *temp = malloc(size);
    memcpy(temp, v + i * size, size);
    memcpy(v + i * size, v + j * size, size);
    memcpy(v + j * size, temp, size);
    free(temp);
}

int main(int argc, char *argv[])
{
    char string[] = "Test string";
    swap(string, 0, 1, sizeof *string);
    puts(string);
    return 0;
}

However the generic version cannot "printf" anything, because swap() don't know how to interpret the bytes. For example, is 0000000011111111 one short or two chars? You have't told it that.

You can also write something dirty with _Generic macro in C11. If your program doesn't have to be strictly conforming, you can take advantage of typeof().

nalzok
  • 14,965
  • 21
  • 72
  • 139
  • Do avoid causing memory leak! Do `free(temp);` in the generic version. – MikeCAT Feb 21 '16 at 03:42
  • Doing arithmetic with `void*` is GCC extension and not in the standard. http://stackoverflow.com/questions/3523145/pointer-arithmetic-for-void-pointer-in-c – MikeCAT Feb 21 '16 at 03:46