This is an extract of a code, where I populate a list with the elements of an array.
#include <stdlib.h>
#include <stdio.h>
#include "../../lib/kernel/list.h"
#include "./listpop.h"
struct item {
struct list_elem elem;
int value;
int priority;
};
void populate(struct list * l, int * a, int n);
void populate(struct list * l, int * a, int n)
{
int i = 0;
while(i != n) {
struct item * newitem = malloc(sizeof(struct item));
newitem->value = a[i];
list_push_back(l,newitem);
i++;
}
}
void test_assignment_1()
{ struct list our_list;
list_init(&our_list);
populate(&our_list, ITEMARRAY, ITEMCOUNT);
}
Code inside list.h:
/* List element. */
struct list_elem
{
struct list_elem *prev; /* Previous list element. */
struct list_elem *next; /* Next list element. */
};
/* List. */
struct list
{
struct list_elem head; /* List head. */
struct list_elem tail; /* List tail. */
};
void list_init (struct list *);
Code inside list.c:
/* Initializes LIST as an empty list. */
void
list_init (struct list *list)
{
ASSERT (list != NULL);
list->head.prev = NULL;
list->head.next = &list->tail;
list->tail.prev = &list->head;
list->tail.next = NULL;
}
And finally, the code inside listpop.h:
#define ITEMCOUNT 10
int ITEMARRAY[ITEMCOUNT] = {3,1,4,2,7,6,9,5,8,3};
Here are the warnings I get:
warning: implicit declaration of function ‘malloc’
warning: incompatible implicit declaration of built-in function ‘malloc’
So far, all I've read about those warnings is to add stdlib.h, but as you can see from my code I've already done it, and the code still give me those warnings. I've restarted the code many times, so the error lays somewhere in the code.
Anyone knows what is not working here?
You might be compiling on a obsolete system with a non conforming compiler and/or C library. Try including <malloc.h> in addition to <stdlib.h> and always include the standard headers first.
Related
I am getting the following error when I try to call the function that should initialize my linked list.
passing argument 1 of 'init_list' from incompatible pointer type [-Wincompatible-pointer-types]
init_list(list);
I do not understand why I am getting this error. This is my first time working with linked lists so any help is appreciated.
Here is how I set up my linked list along with the prototype for my function:
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
typedef char DATA_TYPE;
typedef struct node_t
{
DATA_TYPE item;
struct node_t* next;
} node;
typedef struct
{
node* head;
int len;
} linkedlist_t;
void init_list(linkedlist_t* plist);
This is the function:
void init_list(linkedlist_t* plist)
{
plist->head = (node *)malloc(sizeof(node));
plist->head->next = NULL;
plist->len = 0;
}
And this is how I called the function in main.
#include "linkedlist.h"
int main(void) {
node list;
init_list(&list);
return 0;
}
You are passing a node where your function expects a linkedlist. These two objects are not compatible, because a node is only a part of a linkedlist.
If your init_list function only initializes the node part, then you should change the signature to expect a node instead and maybe also rename it to init_node which would make the code clearer to understand for a reader.
void init_node(node *plist);
Otherwise change list to be of type linkedlist.
linkedlist_t list;
init_list(&list);
I am trying to make a Doubly Linked List in C.
And I get a Segmentation Fault even though I use malloc.
Here is my code so far.
list.h
#ifndef _LIST_
#define _LIST_
typedef struct listnode
{
char * data;
struct listnode * next;
struct listnode * prev;
}listnode;
typedef struct list
{
listnode * firstnode; // it will point to the first element in the list
int size; // the size of the list
}list;
list create_list();
void insert_first_element(char *, list);
#endif
list.c
#include "list.h"
#include <stdlib.h>
#include <string.h>
list create_list()
{
list L;
L.firstnode= NULL;
L.size = 0;
return L;
}
void incert_first_element(char * d, list L)
{
listnode * N= (listnode *)malloc(sizeof(listnode));
strcpy(N->data, d); // <-- I get Segmentation Fault Here
if(L.firstnode != NULL)
{
N->next=L.firstnode;
N->prev=L.firstnode->prev;
L.firstnode->prev=N;
L.firstnode=N;
}
else
{
N->next=NULL;
N->prev=N;
L.firstnode=N;
}
L.size++;
return 0;
}
main.c
#include <stdio.h>
#include "list.h"
int main(void)
{
list L = create_list();
incert_first_element("test",L);
return 0;
}
Any idea what is causing the Segmentation Fault?
Because any problems I found when googling were caused by the lack of malloc, but here I do implement it.
this code
listnode * N= (listnode *)malloc(sizeof(listnode));
strcpy(N->data, d); // <-- I get Segmentation Fault Here
allocates a listnode structure but the data field is a pointer on a char, so it's not initialized by the malloc call.
The second line should be replaced for instance by a strdup call
N->data = strdup(d);
deallocation should also be done in 2 passes. First free(N->data) then free(N)
There are multiple problems in your code:
incert_first_element receives a copy of the list structure and modifies it. This has no effect on the list object of the caller. You should instead pass a pointer to the caller's list object.
the incert_first_element function allocates a new listnode object, but not for the string. The member data is a pointer, not an array, malloc() does not initialize it so strcpy(N->data, d); copies the characters into an uninitialized pointer, invoking undefined behavior (a segmentation fault stooping the program). You should allocate a copy of the string with N-strcpy(N->data, d);
you insert the node at the beginning of the doubly linked list, thus it is incorrect to set N->prev = N; the previous node should be set to NULL in both cases.
in list.c, you should #include "list.h" after the standard headers.
Here is a modified version:
list.h
#ifndef LIST_H
#define LIST_H
typedef struct listnode {
char *data;
struct listnode *next;
struct listnode *prev;
} listnode;
typedef struct list {
listnode *firstnode; // it will point to the first element in the list
int size; // the size of the list
} list;
list create_list(void);
void insert_first_element(list *, const char *);
#endif
list.c
#include <stdlib.h>
#include <string.h>
#include "list.h"
list create_list(void) {
list L = { NULL, 0 };
return L;
}
void insert_first_element(list *L, const char *d) {
listnode *N = malloc(sizeof(*N));
if (N == NULL) {
return -1;
}
N->data = strdup(d);
N->prev = NULL;
N->next = L->firstnode;
if (L->firstnode != NULL) {
L->firstnode->prev = N;
}
L->firstnode = N;
L->size++;
return 0;
}
main.c
#include <stdio.h>
#include "list.h"
int main(void) {
list L = create_list();
insert_first_element(&L, "test");
return 0;
}
I have a requirement to implement two functions
directed_by(node_t * list, char * director)
rated(node_t * list, const rating_t rating)
Each will require I pass in a list and iterate through it. I'm new to C and actually I'm not that familiar with list structures either. Can someone please help me understand how do I return a list so that I can pass into my two functions so that I can iterate through each list?
Here is my code so far. I think I need to return something in my add_movie() function, such as node_t, but I'm not sure how to do that?
LIST.H
#ifndef BASICLIST_H_
#define BASICLIST_H_
typedef struct node {
void * data; /* pointer to data */
struct node * next; /* pointer to next next node */
} node_t;
int list_add(node_t ** list, void * data);
#endif
MOVIE.H
#include <stdio.h>
#ifndef MOVIE_H
#define MOVIE_H
#define SIZE_LIMIT 25
#define RATING_SIZE 6
typedef struct {
char title[SIZE_LIMIT];
char director[SIZE_LIMIT];
char rating[RATING_SIZE];
//rating_t rating;
int year;
}movie_t;
void get_movie(movie_t * movie);
void print_movie(const movie_t *m);
void print_movies(const movie_t *m);
void add_movie(movie_t movie);
#endif /* MOVIE_H */
LIST.C
#include <stdio.h>
#include <stdlib.h>
#include"basiclist.h"
int list_add(node_t ** list, void * data) {
int ret = 0;
node_t * newnode = (node_t *) malloc(sizeof(node_t));
if (newnode == NULL) {
ret = -1;
}
else {
newnode->data = data;
newnode->next = *list;
}
*list = newnode;
return ret;
}
MOVIE.C
#include <stdio.h>
#include <stdlib.h>
#include "movie.h"
#include "basiclist.h"
void print_movies(const movie_t *m) {
printf("%s\t%s\t%s\t%d\n", m->title, m->director, m->rating, m->year);
}
void add_movie(movie_t movie) {
node_t * list = NULL;
movie_t first_movie = movie;
movie_t * new_movie;
new_movie = malloc(sizeof (*new_movie));
*new_movie = first_movie;
list_add(&list, new_movie);
node_t * curr;
curr = list;
while (curr != NULL) {
print_movies(curr->data);
curr = curr->next;
}
}
MAIN.C
#include "movie.h"
#include <stdlib.h>
#include <stdio.h>
#include "basiclist.h"
int main(void) {
movie_t movie1 = {"Movie1", "Director1", "PG-13", 1900};
movie_t movie2 = {"Movie2", "Director2", "R", 1900};
movie_t movie3 = {"Movie3", "Director3", "G", 1900};
movie_t movie4 = {"Movie4", "Director4", "R", 1900};
add_movie(movie1);
add_movie(movie2);
add_movie(movie3);
add_movie(movie4);
/*undefined methods
directed_by(node_t * list, char * director)
rated(node_t * list, const rating_t rating)
*/
return 0;
}
The main problem with this code is that you are not returning or passing your list to the add_movie function.
In each call you are creating a new list and losing it's reference, so you can't use it.
The "easy" fix to your code would be to change:
void add_movie(movie_t movie)
to
void add_movie(node_t** list, movie_t movie);
and remove the first line of the function, then change your main to:
node_t* list = NULL;
add_movie(&list, movie1);
add_movie(&list, movie2);
add_movie(&list, movie3);
add_movie(&list, movie4);
With this change you will have the list with movie4, movie3, movie2 and movie1.
PS: you also want to change your list add method to return -1 instead of setting ret to -1. In its current form you would lose your list in case of an error because you are setting the given reference to NULL (also, that would create a memory leak).
PS 2: It is not really recommended to pass structs as arguments in C, you should use pointers instead. The reason is that when you pass a struct as argument C will copy its whole content to a temporary struct variable, so if you have, say, a 256 bytes struct you will be copying 256 bytes of information for every function call, instead of 4 (32 bits systems) or 8 (64 bits systems) if you had used a pointer.
I'm new to C been at it about two weeks, hitting a few problems with linked lists and hash tables. The compilier is throwing a few errors:
I've tried to mark these in the source code.
finddupl.c: In function 'main':
finddupl.c:35:5: warning: assignment from incompatible pointer type
finddupl.c:37:3: warning: passing argument 1 of 'ml_lookup' from incompatible pointer type
mlist.h:19:9: note: expected 'struct MList *' but argument is of type 'struct MList *'
mlist.c: In function 'ml_lookup':
mlist.c:63:37: warning: assignment from incompatible pointer type
mlist.c: In function 'ml_add':
mlist.c:78:9: error: request for member 'hashtable' in something not a structure or union
mlist.c:90:12: warning: assignment from incompatible pointer type
Can anyone guide me in the right direction here, I've been at this for a few hours
Not loving C so far :p
I've left out the mentry.c and the c file with the main function, I've tested both of these before I tried to write the hash table.
Mentry.h
#ifndef _MENTRY_INCLUDED_
#define _MENTRY_INCLUDED_
#include <stdio.h>
typedef struct mentry {
char *surname;
int house_number;
char *postcode;
char *full_address;
} MEntry;
/* me_get returns the next file entry, or NULL if end of file*/
MEntry *me_get(FILE *fd);
/* me_hash computes a hash of the MEntry, mod size */
unsigned long me_hash(MEntry *me, unsigned long size);
/* me_print prints the full address on fd */
void me_print(MEntry *me, FILE *fd);
/* me_compare compares two mail entries, returning <0, 0, >0 if
* me1<me2, me1==me2, me1>me2
*/
int me_compare(MEntry *me1, MEntry *me2);
#endif /* _MENTRY_INCLUDED_ */
mlist.h
#ifndef _MLIST_INCLUDED_
#define _MLIST_INCLUDED_
#include "mentry.h"
typedef struct mlist MList;
extern int ml_verbose; /* if true, prints diagnostics on stderr */
/* ml_create - created a new mailing list */
struct MList *ml_create(void);
/* ml_add - adds a new MEntry to the list;
* returns 1 if successful, 0 if error (malloc)
* returns 1 if it is a duplicate */
int ml_add(MList **ml, MEntry *me);
/* ml_lookup - looks for MEntry in the list, returns matching entry or NULL */
MEntry *ml_lookup(struct MList *ml, MEntry *me);
#endif /* _MLIST_INCLUDED_ */
mlist.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mentry.h"
#include "mlist.h"
#define HASHSIZE 101
struct Mlist_node{
MEntry *me;
MEntry *next;
int size;
};
struct Mlist_head{
struct Mlist_node *head;
struct Mlist_node *tail;
};
struct MList{
int size;
struct Mlist_head hashtable[HASHSIZE];
};
struct MList *ml_create(void){
struct MList *m;
struct Mlist_head *h;
int i;
if ((m = ( struct MList *)malloc(sizeof(struct MList))) != NULL){
if ((h = (struct Mlist_head *)malloc(sizeof(struct Mlist_head))) != NULL) {
for (i = 0; i < HASHSIZE; i++) {
h = &(m->hashtable[i]);
h->head = NULL;
h->tail = NULL;
}
printf("worked");
return m;
}
}
printf("fail");
return NULL;
}
MEntry *ml_lookup(struct MList *ml, MEntry *me){
struct Mlist_node *mn;
struct Mlist_head *mh;
if ((mn = (struct Mlist_node *)malloc(sizeof(struct Mlist_node))) != NULL) {
if ((mh = (struct Mlist_head *)malloc(sizeof(struct Mlist_head))) != NULL) {
unsigned hashval = me_hash(me,HASHSIZE);
printf("%d",hashval);
mh=&(ml->hashtable[hashval]);
for (mn = mh->head; mn != NULL; mn = mn->next) //LINE 63 ERROR
if (me_compare(mn->me, me) == 0)
return me; /* found */
}
}
return NULL;
}
int ml_add(MList **ml, MEntry *me){
unsigned hashval;
struct Mlist_head *mh;
struct Mlist_node *mn;
hashval = me_hash(me,HASHSIZE);
mh = ml->hashtable[hashval]; //LINE 78 ERROR
if ((mn = (struct Mlist_node *)malloc(sizeof(struct Mlist_node))) != NULL){
mn->me=me;
if(mh->head==NULL){
mh->head=mn;
mh->tail=mn;
mn->next=NULL;
}
else{
mn = mh->tail;
mn->next=me;
mh->tail=me; /LINE 90 ERROR
}
return 1;
}
else{
printf("failed to allocate memory");
return 0;
}
/* not found */
}
Look into how you're forward declaring MList in mlist.h. You use the syntax
typedef struct mlist MList;
This looks a little off to me. You're declaring a type of name MList. Note that with the above style of declaration, the compiler expects to see "struct mlist" or just the type name's MList when referring to this struct. (This question may be helpful to you). However later on you definen a struct MList as follows:
struct MList{
int size;
struct Mlist_head hashtable[HASHSIZE];
};
Which makes the compiler expect afterwords to see things referred to with "struct MList". But in your fwd declaration, you just said that plain old "MList" without the struct is ok. The compiler may or may not be able to make sense of this confusion between the fwd declaration and your definition. Its made worse in that one is a tag name of the struct and the other is the struct's canonical name. This kind of thing makes my spidy sense tingle that something could be off and causing confusion between you and the compiler.
I would just change how you forward declare to be consistent with how Mlist is used and see if that helps you. To do this change the above line to:
struct MList;
(then notice in mlist.h how you inconsistently use the struct keyword when referring to MList. Sometimes you do and sometimes you don't. this may also be causing problems w/ confusing your compiler. If you change to the above fwd declaration, use struct MList, not just MList)
In other news, for:
mlist.c:63:37: warning: assignment from incompatible pointer type
You're assigning a MEntry to a MNode, which are of different types, so I would expect you to get the warning you're getting.
I've been trying to figure out pointers in C most of today, even asked a question earlier, but now I'm stuck on something else. I've got the following code:
typedef struct listnode *Node;
typedef struct listnode {
void *data;
Node next;
Node previous;
} Listnode;
typedef struct listhead *LIST;
typedef struct listhead {
int size;
Node first;
Node last;
Node current;
} Listhead;
#define MAXLISTS 50
static Listhead headpool[MAXLISTS];
static Listhead *headpoolp = headpool;
#define MAXNODES 1000
static Listnode nodepool[MAXNODES];
static Listnode *nodepoolp = nodepool;
LIST *ListCreate()
{
if(headpool + MAXLISTS - headpoolp >= 1)
{
headpoolp->size = 0;
headpoolp->first = NULL;
headpoolp->last = NULL;
headpoolp->current = NULL;
headpoolp++;
return &headpoolp-1; /* reference to old pointer */
}else
return NULL;
}
int ListCount(LIST list)
{
return list->size;
}
Now in a new file I have:
#include <stdio.h>
#include "the above file"
main()
{
/* Make a new LIST */
LIST *newlist;
newlist = ListCreate();
int i = ListCount(newlist);
printf("%d\n", i);
}
When I compile, I get the following warning (the printf statement prints what it should):
file.c:9: warning: passing argument 1 of ‘ListCount’ from incompatible pointer type
Should I be worried about this warning? The code seems to do what I want it to, but I'm obviously very confused about pointers in C. After browsing questions on this site, I found that if I make the argument to ListCount (void *) newlist, I don't get the warning, and I don't understand why, nor what (void *) really does...
Any help would be appreciated, thanks.
You're getting confused because of multiple typedefs. LIST is a type representing a pointer to struct listhead. So, you want your ListCreate function to return a LIST, not a LIST *:
LIST ListCreate(void)
The above says: ListCreate() function will return a pointer to a new list's head if it can.
Then you need to change the return statement in the function definition from return &headpoolp-1; to return headpoolp-1;. This is because you want to return the last available head pointer, and you have just incremented headpoolp. So now you want to subtract 1 from it and return that.
Finally, your main() needs to be update to reflect the above changes:
int main(void)
{
/* Make a new LIST */
LIST newlist; /* a pointer */
newlist = ListCreate();
int i = ListCount(newlist);
printf("%d\n", i);
return 0;
}