0

I have this code:

typedef struct node
{
    char* data;
    struct node next;
} node;

typedef struct linkedList
{
    node head;
    int size;
} linkedList;

typedef struct _MyLinkedList *MyLinkedListP
{
    struct linkedList* listp;
};

MyLinkedListP createList()
{
    linkedList *list = (linkedList*)malloc(sizeof(linkedList));
    (*list).head = NULL;
    (*list).size = 0;
    MyLinkedListP listP = list;
    return listP;
}

I am trying to build a function:

MyLinkedListP cloneList(MyLinkedListP l)

l is a pointer to a linkedList, I am trying to get its members (size and first node), in order to complete the function. But I just do not understand how to do it under this build. I also want to ask regarding my build of struct MyLinkedListP. My goal was to create a type that is a pointer to a linkedList, is the way I did it good practice?

Edgar Rokjān
  • 17,245
  • 4
  • 40
  • 67
Eyzuky
  • 1,843
  • 2
  • 22
  • 45
  • 2
    [Please see this discussion on why not to cast the return value of `malloc()` and family in `C`.](http://stackoverflow.com/q/605845/2173917). – Sourav Ghosh Aug 16 '16 at 18:52
  • Do not use identifiers starting with underscore then a capital letter; they are reserved for the implementation. Do not cast the result of `malloc`. – aschepler Aug 16 '16 at 18:53
  • 1
    `struct node next;` --> `struct node *next;` and `node head;` --> `node *head;` Don't you get compiler warnings? – Weather Vane Aug 16 '16 at 19:06
  • The arrow `->` operator was invented so that you wouldn't have to use `(*ptr).member` notation. It also nests more cleanly: `ptr->memberptr->member` vs `(*(*ptr).memberptr).member` (and if there's a mistake in the nested dotted notation, it only reinforces the easier readability of the arrow notation). – Jonathan Leffler Aug 16 '16 at 19:09
  • Incdidentally, the lines `typedef struct _MyLinkedList *MyLinkedListP { struct linkedList* listp; };` don't compile, do they? You could place a semicolon after the P and what goes before would be clean. You would have to provide a `struct DoHickey` line before the body of the structure definition, though (for some value of `DoHickey`) before the second part of that fragment could compile. – Jonathan Leffler Aug 16 '16 at 19:19
  • _l is a pointer to a linkedList_ - no. `l` has a member `listp`, a pointer to a linkedList. – alvits Aug 16 '16 at 19:33

2 Answers2

2

First of all, this won't work:

typedef struct node
{
  char* data;
  struct node next;
} node;

A struct type may not contain a member that's an instance of itself1; this should be written as

typedef struct node
{
  char* data;
  struct node *next;  // next is a *pointer* to struct node
} node;

Secondly, while the following isn't a problem like the above, this is not good practice:

typedef struct _MyLinkedList *MyLinkedListP

Identifiers with leading underscores are reserved for the implementation; you should not create any type or object names with leading underscores. Just use

typedef struct MyLinkedList *MyLinkedListP

instead2.

Third, lose the cast in

linkedList *list = (linkedList*)malloc(sizeof(linkedList));

It's not necessary (since C89), it clutters up the call, and it creates maintenance headaches. That can be made much simpler as follows:

linkedList *list = malloc( sizeof *list );

Fourth, note that you can write

(*list).head = NULL;
(*list).size = 0;

as

list->head = NULL;
list->size = 0;

a->b is shorthand for (*a).b, and makes things a little easier to read.

Finally,

MyLinkedListP listP = list;

is attempting to assing a value of type struct linkedList * to an object of type struct MyLinkedList *, and they aren't compatible. Based on the code you've shared, it looks like you meant to do something more like

struct MyLinkedList myList;
list.listp = list;

or

struct MyLinkedList myList = {list};

or even

MyLinkedListP listP = malloc( sizeof *listP ); // leaky abstraction from hiding
                                               // pointer behind typedef

listP->listp = list;

I suggest you take a step back and try to simplify what you're doing - you've added a bit of unnecessary complexity with your types.


  1. First of all, the struct node type isn't complete until the closing } of the struct definition, and you can't declare an instance of an incomplete type; you can, however, declare a pointer to an incomplete type. Secondly, the size to store an instance of struct node would have to be infinite, since the instance contains an instance of itself, which contains an instance of itself, which contains an instance of itself, etc.
  2. A quick rant - as a rule, you should not hide pointers behind typedefs. If the programmer has to ever be aware that they are dealing with a pointer (for example, if they need to access members of the struct type), then make that explicit in the declaration of the pointer object (look at the FILE type in stdio.h as an example - even though you only ever deal with pointers to FILEs, that pointer is not part of the FILE typedef).

John Bode
  • 119,563
  • 19
  • 122
  • 198
0

The definition of struct node won't compile, because it is trying to contain itself in its definition. Instead, use indirection via a pointer.

typedef struct node
{
    char* data;
    struct node *next;
} node;

The definition of struct _MyLinkedList is incorrect, since the body has to follow the tag. Mirror your syntax for struct node and place the alias after the struct declaration.

typedef struct _MyLinkedList
{
    struct linkedList* listp;
} *MyLinkedListP;

Since the head member of struct linkedList is not a pointer variable, the assignment will not compile. If you meant for the assignment to succeed, then change the definition of struct linkedList accordingly.

typedef struct linkedList
{
    node *head;
    int size;
} linkedList;

Your are assigning a struct linkedList * to a struct _MyLinkedList *, but they are not compatible. Since your function wants to return a struct _MyLinkedList *, you should properly allocate one to be returned.

MyLinkedListP listP = malloc(sizeof(*listP));
listP->listp = list;
return listP;

With all the changes together, and fixing up some stylistic issues:

typedef struct node
{
    char* data;
    struct node *next;
} node;

typedef struct linkedList
{
    node *head;
    int size;
} linkedList;

typedef struct _MyLinkedList
{
    struct linkedList* listp;
} *MyLinkedListP;

MyLinkedListP createList()
{
    linkedList *list = malloc(sizeof(*list));
    list->head = NULL;
    list->size = 0;
    MyLinkedListP listP = malloc(sizeof(*listP));
    listP->listp = list;
    return listP;
}
jxh
  • 69,070
  • 8
  • 110
  • 193