-2

In the below code, I am using a single swap function to swap two types of data. But I am getting lots of error.

Can anyone help me that where I am doing wrong?

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

//Structure definition which I am trying to swap.

struct swapNum
{
    int sal;
    char *c;
};

//The swap function which I am using to swap with void function parameters.

void swap(void *a,void *b, int size)
{
    if(size == sizeof(*a))
    {
        struct swapNum temp;
        memcpy(temp,a,sizeof(*a));
        memcpy(a,b,sizeof(*b));
        memcpy(b,temp,sizeof(*temp));
    }
    if(size == sizeof(int))
    {
        int *temp;
        *temp = *a;
        *a = *b;
        *b = *a;
    }
}

The main driver part of program.

int main(void) {
    char a[10] = "vivek";
    char b[10] = "mishra";
    struct swapNum *A= malloc(sizeof(struct swapNum));
    struct swapNum *B = malloc(sizeof(struc swapNum));
    A->sal = 23;
    A->c = a;

    B->sal = 64;
    B->c = b;

    swap(&A,&B,sizeof(A));

    int x=10,y=20;
    swap(&x,&x,sizeof(b));
    printf("After swapping x : %d y: %d",x,y);

    return 0;
}

The errors which I am getting.

prog.c: In function 'swap':
prog.c:16:9: error: incompatible type for argument 1 of 'memcpy'
         memcpy(temp,a,sizeof(*a));
         ^
In file included from prog.c:2:0:
/usr/include/string.h:46:14: note: expected 'void * __restrict__' but     argument is of type 'struct swapNum'
 extern void *memcpy (void *__restrict __dest, const void *__restrict __src,
              ^
prog.c:18:30: error: invalid type argument of unary '*' (have 'struct     swapNum')
         memcpy(b,temp,sizeof(*temp));
                              ^
prog.c:18:9: error: incompatible type for argument 2 of 'memcpy'
         memcpy(b,temp,sizeof(*temp));
         ^
In file included from prog.c:2:0:
/usr/include/string.h:46:14: note: expected 'const void * __restrict__' but     argument is of type 'struct swapNum'
 extern void *memcpy (void *__restrict __dest, const void *__restrict __src,
              ^
prog.c:23:9: warning: dereferencing 'void *' pointer
         *temp = *a;
         ^
prog.c:23:17: warning: dereferencing 'void *' pointer
         *temp = *a;
                 ^
prog.c:23:9: error: invalid use of void expression
         *temp = *a;
         ^
prog.c:24:9: warning: dereferencing 'void *' pointer
         *a = *b;
         ^
prog.c:24:14: warning: dereferencing 'void *' pointer
         *a = *b;
              ^
prog.c:2
4:9: error: invalid use of void expression
     *a = *b;
         ^
prog.c:25:9: warning: dereferencing 'void *' pointer
     *b = *a;
     ^
prog.c:25:14: warning: dereferencing 'void *' pointer
         *b = *a;
              ^
prog.c:25:9: error: invalid use of void expression
         *b = *a;
         ^
prog.c: In function 'main':
prog.c:33:36: error: 'struc' undeclared (first use in this function)
  struct swapNum *B = malloc(sizeof(struc swapNum));
                                    ^
prog.c:33:36: note: each undeclared identifier is reported only once for     each function it appears in
prog.c:33:42: error: expected ')' before 'swapNum'
  struct swapNum *B = malloc(sizeof(struc swapNum));
                                          ^
Vivek
  • 207
  • 1
  • 4
  • 17
  • why not try with `void swap(struct swapNum *a, struct swapNum *b, int size)`? – yano Feb 15 '17 at 19:56
  • 1
    why don't you print out what `sizeof(*a)` is, so you can see what the compiler thinks the size of a dereferenced void pointer is. – bruceg Feb 15 '17 at 19:57
  • @yano If I use void swap(struct swapNum *a,struct swapNum *b, int size) then this function will never be able to swap two integers. – Vivek Feb 15 '17 at 19:58
  • Since you are getting compilation errors, you should post them. – jxh Feb 15 '17 at 20:00
  • Also, shouldn't `swap(&x,&x,sizeof(b));` really be: `swap(&x,&x,sizeof(int));`? – bruceg Feb 15 '17 at 20:02
  • @jxh I posted errors – Vivek Feb 15 '17 at 20:06
  • @bruceg sizeof(b) or sizeof(int) both are going to be same. – Vivek Feb 15 '17 at 20:09
  • 1
    Your errors don't really match to code you have posted. – jxh Feb 15 '17 at 20:10
  • 1
    [fix code](http://ideone.com/apFhMy) – BLUEPIXY Feb 15 '17 at 20:10
  • 1
    The `sizeof` is evaluated at compile time. The compiler will have no idea what the size of the target of a `void*` pointer will be at run time. Why don't you just provide 2 functions? Even better, a swap operation for a `struct` or `int` is trivial, and can be done inline without any function. – Weather Vane Feb 15 '17 at 20:11
  • @jxh Sorry, Edited the error part. – Vivek Feb 15 '17 at 20:15
  • ... you do not even need `memcpy` to copy a `struct`. You just equate it, as you do with `int` (but cannot do with strings). – Weather Vane Feb 15 '17 at 20:18
  • Can you focus on one of the compilation errors, and try to fix it yourself? If you don't understand what the error means, try posting a new question about the error, what you thought it meant, and how you tried to correct it. – jxh Feb 15 '17 at 20:20
  • I think the broad problem here is you're trying to write a one-size-fits-all function. If you want to swap structs, write a function that does that. If you want to swap ints, write a function that does that. A function should do one thing and do it well. If you've got a bunch of different data types you want to swap and don't want a unique swap function for each one, perhaps c++ with its inheritance and polymorphism is a better language choice. `void*` should generally be avoided. Besides, just because the size of something equals `sizeof(int)` doesn't mean it is an `int`, for example. – yano Feb 15 '17 at 20:31
  • @vivek in main the size of b is a char[10] which is most likely 10. So, unless you are on a system with 10 byte integers, I don't think that b and int are the same size. – bruceg Feb 15 '17 at 21:21

2 Answers2

0

There are two problems:

struct swapNum *A= malloc(sizeof(struct swapNum));
struct swapNum *B = malloc(sizeof(struc swapNum));
A->sal = 23;
A->c = a;

B->sal = 64;
B->c = b;

swap(&A,&B,sizeof(A));

sizeof(A) returns the size of a pointer, you need sizeof(*A) in order to get the correct size of the object.

And you don't want the address of &A and &B because they are already pointers, change to

swap(A,B,sizeof(*A));

The second problem is in the swap function:

void swap(void *a,void *b, int size)
{
    if(size == sizeof(*a))
    { ...

Compile with warnings:

warning: invalid application of ‘sizeof’ to a void type

As suggested by @BLUEPIXY in comments, use a temporary:

void swap(void *a,void *b, size_t size)
{
    void *temp = malloc(size);

    if (temp) {
        memcpy(temp, a, size);
        memcpy(a, b, size);
        memcpy(b, temp, size);
        free(temp);
    }
}
David Ranieri
  • 39,972
  • 7
  • 52
  • 94
  • I changed it, but I am still getting errors. prog.c:16:9: error: incompatible type for argument 1 of 'memcpy' memcpy(temp,a,sizeof(a)); ^ prog.c:18:9: error: incompatible type for argument 2 of 'memcpy' memcpy(b,temp,sizeof(temp)); ^ prog.c:23:9: warning: dereferencing 'void *' pointer *temp = *a; ^ prog.c:23:17: warning: dereferencing 'void *' pointer *temp = *a; ^ prog.c:23:9: error: invalid use of void expression *temp = *a; ^ – Vivek Feb 15 '17 at 20:22
0

Here is a way to implement a generic swap function that doesn't require malloc for your temporary:

void swap_by_bytes (void *a, void *b, size_t sz) {
    char tmp;
    char *ap = a;
    char *bp = b;
    while (sz--) {
        tmp = *ap;
        *ap++ = *bp;
        *bp++ = tmp;
    }
}

While byte by byte works fine, you might be able to improve things by copying word for word.

void swap_by_words (void *a, void *b, size_t sz) {
    unsigned tmp;
    char *ap = a;
    char *bp = b;
    while (sz >= sizeof(tmp)) {
        memcpy(&tmp, ap, sizeof(tmp));
        memmove(ap, bp, sizeof(tmp));
        memcpy(bp, &tmp, sizeof(tmp));
        ap += sizeof(tmp);
        bp += sizeof(tmp);
        sz -= sizeof(tmp);
    }
    if (sz > 0) swap_by_bytes(ap, bp, sz);
}

If the size is not a multiple of the word size, the remainder is swapped by bytes. Notice the use of memmove just in case a and b overlap.

Finally, you can use VLA if your platform supports it. However, C.2011 has made VLA an optional feature, so you have to test for its availability.

void swap (void *a, void *b, size_t sz) {
#ifdef __STDC_NO_VLA__
    swap_by_words(a, b, sz);
#else
    char tmp[sz];
    memcpy(tmp, a, sz);
    memmove(a, b, sz);
    memcpy(b, tmp, sz);
#endif
}
jxh
  • 69,070
  • 8
  • 110
  • 193