4

I use the read() function to read in 40 characters from a file, and need to copy from the offset of 10 for the length of 20. In other words, I need to do memcpy from the 10th to 30th characters into a new memory address. When I run my code (see following), however, I got the warning message: warning: dereferencing ‘void *’ pointer

int main()
{
    void *buffer = malloc(40);
    int fd = open("example20.txt", O_RDONLY);
    printf("the value of fd is %d \n", fd);


/* read 40 characters from the file */ 
int bytes_read = read(fd, buffer, 40);

void *new_container = malloc(20);

/* copy from buffer, starting offset at 10 for length of 20 */
memcpy(new_container, &buffer[10], 20);
printf("new_container is %s \n", (char *) new_container);

return 0;
}

I am wondering what this error means, and how to fix it?

edit1: I found a way of solving the problem: by casting the buffer from void* to a new char* pointer.

char *buffer2 = (char *) buffer;
memcpy(new_container, &buffer2[10], 20);

edit2: I found a way of using void* pointer in memcpy: memcpy(new_container, buffer+10, 20); the variable "buffer" in this way can be a void* type

TonyW
  • 18,375
  • 42
  • 110
  • 183

3 Answers3

7

Change the line

memcpy(new_container, &buffer[10], 20);

to

memcpy(new_container, (char *)buffer + 10, 20);

That's because &buffer[10] evaluates to&(*(buffer + 10)) because the array subscript operator has higher precedence than the address of operator &. However, buffer is of type void * and pointer arithmetic cannot be done on void pointers because there is no size information. Using the typecast operator (char *) on buffer provides the necessary size information so that
(char *)buffer + 10 is equivalent to buffer + 10 * sizeof(char) or the address of the 11th element in the buffer pointed to by the variable buffer.

ajay
  • 9,402
  • 8
  • 44
  • 71
6

The warning is due to this:

&buffer[10]

void has no size, and the [] operator needs a concrete data type to operate in a defined manner. That this is a warning is probably due to your compiler supporting void* in an unsigned char * manner (gcc has this extension, for example). But it isn't standard. Thus the warning.

Change this:

void *buffer = malloc(40);

To this:

unsigned char *buffer = malloc(40);
WhozCraig
  • 65,258
  • 11
  • 75
  • 141
  • thanks for the quick replies. The reason why I needed "buffer" to be a void pointer is my program cannot assume reading strings/characters, sometimes, it could be an mp3 file or other format. I wonder if I can still make "buffer" a char type? – TonyW Apr 17 '14 at 05:42
  • @TonyGW you should have no problem using `unsigned char *` for that effort (and you'll likely find it easier to use/debug in the long run). – WhozCraig Apr 17 '14 at 05:46
  • I found a way of using void* pointer in memcpy: memcpy(new_container, buffer+10, 20); the variable "buffer" in this way can be a void* type – TonyW Apr 17 '14 at 19:56
  • @TonyGW You may skip the warning (and I'm shocked if it does), but the validity of the statement is still supported by extension only. `buffer+10` where `buffer` is `void*` has *no concrete type* on which to perform the pointer arithmetic. `gcc` will do it, but it is **not** standard. To be standard-compliant, you either need to use a typed-pointer, or cast to a typed-pointer type *before* the arithmetic (see ajay's answer for such a cast, this answer for just using a typed-pointer). – WhozCraig Apr 17 '14 at 20:04
3

The error/warning is for line

memcpy(new_container, &buffer[10], 20);

Here you are trying to access 11th element of buffer. But as buffer is void *, doing buffer[10] is not valid.

You need to define it as

char *buffer = malloc(40);

Similarly for new_container.

Rohan
  • 52,392
  • 12
  • 90
  • 87
  • `char *buffer = (char*)malloc(40);` – Iłya Bursov Apr 17 '14 at 05:40
  • 2
    @Lashane: No, Rohan's version is correct, yours is redundant and allows for a subtle error if you forgot to include `stdlib.h` on compilers which allow implicit int. This is C, not C++. There exists an implicit conversion from `void*` to any other type of pointer. No one who actually knows C casts the return value of `malloc`. – Ed S. Apr 17 '14 at 07:12