8

I have a C program that produces an error:

invalid conversion from 'void*' to 'node*' [-fpermissive]

Here's my code:

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

struct node
{
    int data;
    struct node* next;
};

struct node* onetwothree();

int main()
{
    struct node* ptr;
    ptr = onetwothree();
    return 0;
}

struct node* onetwothree()
{
    struct node* head;
    struct node* temp;
    head = malloc(sizeof(struct node));
    temp = head;
    for(int i=1; i<=3; i++)
    {
        temp->data = i;
        if(i<3)
            temp=temp->next;
        else
            temp->next = NULL;
    }
    return head;
}

What am I doing wrong?

Eric Leschinski
  • 146,994
  • 96
  • 417
  • 335
STAR S
  • 81
  • 1
  • 1
  • 2
  • 4
    How sure are you that you're compiling this as C code and not C++ code ? – nos May 28 '13 at 13:42
  • 1
    @Sildoreth Please **do not** edit posts to change the coding style to suit your own subjective preferences. That's just vandalism and doesn't help anyone. Your edit should never have been approved. Edit rollback. – Lundin May 28 '13 at 13:49
  • That being said, the indention of this post is horribly inconsistent and needs a fix. An edit just changing the indention is fine. – Lundin May 28 '13 at 13:52
  • Are you really allocating storage for one `struct node`, and then acting as though you have a linked list of three of them? Please tell me I'm imagining that. – This isn't my real name May 28 '13 at 20:41

3 Answers3

20

In C, a void* is implicity convertible to a T* where T is any type. From section 6.3.2.3 Pointers of the C99 standard:

A pointer to void may be converted to or from a pointer to any incomplete or object type. A pointer to any incomplete or object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer.

malloc() returns a void* and is assignable without casting to head, a struct node*. This is not true in C++, so I suspect a C++ compiler is being used to compile this C code.

For example:

#include <stdlib.h>

int main()
{
    int* i = malloc(sizeof(*i));
    return 0;
}

when compiled with:

gcc -Wall -Werror -pedantic -std=c99 -pthread main.c -o main

emits no errors. When compiled with:

g++ -Wall -Werror -pedantic -std=c++11 -pthread main.cpp -o main

emits:

main.cpp: In function 'int main()': main.cpp:5:31: error: invalid conversion from 'void*' to 'int*' [-fpermissive]


Additionally, the onetwothree() function is not allocating memory correctly. It allocates one struct node only:

head = malloc(sizeof(struct node));

and then, eventually, dereferences head->next->next which is undefined behaviour. An individual malloc() is required for every struct node. Remember to free() what was malloc()d.

hmjd
  • 120,187
  • 20
  • 207
  • 252
  • i can't remember the details, but thought pointers to functions and data weren't inter-changeable in c? is that wrong? should it be "any data type"? – andrew cooke May 28 '13 at 13:49
  • @andrewcooke That's correct. However on our common server/desktop platforms they are, and posix seem to at least implicitly require that void* and function pointers are inter-changeable. – nos May 28 '13 at 13:56
  • @andrewcooke, I will update answer with relevant section from C99 standard, which states _any incomplete or object type_. – hmjd May 28 '13 at 13:56
  • I was getting the same issue because I was using g++ rather than gcc to compile OpenSSL! – Chris Watts Aug 12 '15 at 19:24
10

You're having this warning/error because you are using malloc (which returns a void*)to initialize a structure of type node* without doing an explicit cast.

To get rid of this error you could change your code this way :

head = (struct node *)malloc(sizeof(struct node));

or you could as well add the "-fpermissive" flag to your compiler which will then ignore these errors.

EDIT: But yeah, i didn't think about the fact that this should not happen in a C compiler anyways

Alex Erny
  • 456
  • 2
  • 6
  • 4
    -1, wrong answer. This is C and not C++, in C `void*` converts easily to any pointer to a data type. – Jens Gustedt May 28 '13 at 13:47
  • @JensGustedt if compiled with C++ comilper then even C code will show this error, so it not realy a wrong answer and less worth a downvote. – A4L May 28 '13 at 13:52
  • 3
    @A4L, casting `malloc` in C is never right. It can hide subtle errors, because the compiler assumes that you know what you are doing. C and C++ are different languages and in particular their handling of dynamic allocations differs substantially. That a C++ compiler produces errors on a C code isn't a good argument. – Jens Gustedt May 28 '13 at 13:58
  • 1
    @JensGustedt what kind of error could casting malloc (in C) hide? How can dynamic allocations differ (using only malloc, not new) from C and C++? It's just a wrapper to a syscall, isn't it? – Xaqq May 28 '13 at 14:07
  • @Xaqq, please have a look at the FAQ: http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc – Jens Gustedt May 28 '13 at 19:12
  • @Xaqq The difference between C and C++, is that in C `void*` are used for generic programming and they can be implicitly converted to any other pointer type without yielding an error. In C++ there are other means for generic programming, therefore it can use a stricter type system than C. In C++, you need an explicit cast to cast between `void*` and another pointer type. – Lundin May 29 '13 at 06:14
  • The error that a cast can hide, is when you forget to include on an old C90 compiler. As there is then no prototype visible, the return type of malloc defaults to `int`, instead of `void*`. Compilers will not typically accept conversions from pointer to `int` without an explicit cast and therefore warn, but if you put an explicit cast there, they will not. Now, if the `int` type of the particular system happens to have a different size than the expected `void*`, the program will crash. This is only an issue if you use old C90 compilers. In C99, the implicit int has been removed. – Lundin May 29 '13 at 06:19
  • @Lundin Yeah I know about the use of `void*` in C. However I have to disagree with the fact that you wont get a warning. Calling `malloc()` without including stdlib.h will cause a warning `test.c:3:25: warning: incompatible implicit declaration of built-in function ‘malloc’ [enabled by default]`, event when explicity casting, and compiling with -std=c90 – Xaqq May 29 '13 at 08:27
  • Btw, I have to admit, it's not the same kind of warning, but it should be enough to let most programmers know something's wrong. – Xaqq May 29 '13 at 08:53
  • @Xaqq That's just because you are using a good compiler with a lot of warnings enabled. I'm discussing what will happen in a general C compiler, and not the specific case of GCC. – Lundin May 29 '13 at 11:11
  • @Lundin Okay, that makes sense :) Thought most (if not all) compiler would warn about calling an implicitly declared function. – Xaqq May 29 '13 at 12:06
0

Use:

head = (struct node*) malloc(sizeof(struct node));

C++ does not support implicit conversion of void* returned by malloc(), which C does. You'll need to typecast the return value.

Seemant Singh
  • 142
  • 1
  • 7