Memory Allocation for Function Pointer - c

I have a struct called warehouse and a generic linked list and each item points to a warehouse struct.
typedef struct linked{
char type;
void * item;
struct linked * next;
struct linked * prev;
}LinkedList;
typedef struct warehouse{
char * name;
float volume;
float (* getPrice) (void * S);
float (* getTotalDollarAmount)(void * S);
}house_t;
When I tried to get the getPrice function pointer point to a function float price (void *S)
void menu (LinkedList *house){
char *c;
float num;
c = (char*)malloc(sizeof(char)*10);
LinkedList *i;
i = (LinkedList*)malloc(sizeof(LinkedList);
house_t *sk;
sk = (house_t *) malloc(sizeof(house_t));
//i->item = (house_t *) malloc(sizeof(house_t));
scanf("%c", c);
((house_t*)i->item)->getPrice = price;
sk=findhouse(house, c);
num = ((house_t*)i->item)->getPrice(sk);
printf("%f",num);
}
I got bad access error. Since every time I got a bad access error it was because I didn't allocate memory for something. But do I need to allocate memory for function pointer? If so, how?
Here's some more code
float price (void *S)
{
return ((house_t*)S)->volume;
}

LinkedList *i;
i = NewLinkedList();
/* ... snip ... */
LinkedList *NewLinkedList()
{
return NULL;
}
According to your definition of NewLinkedList(), the variable i is now NULL. You try and dereference it with i->item = ... but you can't do this if i is NULL. I think what you really want to do is allocate space for your linked list in your NewLinkedList function:
LinkedList * NewLinkedList()
{
LinkedList *result = malloc(sizeof(LinkedList));
result->type = '\0'; // set to suitable initial value
result->item = NULL;
result->next = NULL;
result->prev = NULL;
return result;
}

Related

Print void pointer in a Linked List

I have an array of structs called arrayOfElements , the structs are called Elements which have a void pointer
typedef struct {
void* data;
} Element;
Ive malloc'd arrayOfElements
Element* arrayOfElements;
arrayOfElements= malloc(4 * sizeof(Element));
and have stored ints and strings in the strucs
arrayOfElements[3].data = malloc( sizeof(int) );
ptr = arrayOfElements[3].data;
*ptr = 65;
strcpy(arrayOfElements[1].data, token );
Then I have created a Linked List
typedef struct LinkedList {
void* arrayOfStruct;
struct LinkedList* next;
} LinkedList;
And have created a function to import a instance of arrayOfELements and make void* arrayOfStruct point to it
LinkedList* insert(LinkedList* head, Element* inArrayOfElements) {
LinkedList* insertNode = malloc(sizeof(LinkedList));
insertNode->next = head;
insertNode->arrayOfStruct = (void*)inArrayOfElements;
return insertNode;
}
Question
My question is after I have pointed void* arrayOfStruc to an instance of arrayOfELements, how do I print void* data of arrayOfElements[3] which I know from before is an int and its value is 65
Current Node in LinkedList ---> arrayOfElements[3] --> data member in Element struct (should equal 65)
I have a feeling I should point a int pointer to it and then print that, but Im not sure the syntax to do it
You need some way of knowing what kind of data the data member points to. An additional element denoting the type would work.
typedef enum {
STR_TYPE,
INT_TYPE,
...
} data_type;
typedef struct {
data_type type;
void* data;
} Element;
Then you can set the element like this:
arrayOfElements[3].type = INT_TYPE;
arrayOfElements[3].data = malloc( sizeof(int) );
int *ptr = arrayOfElements[3].data;
*ptr = 65;
arrayOfElements[1].type = STR_TYPE;
strcpy(arrayOfElements[1].data, token );
and read it like this:
Element *curr = &list_node->arrayOfStruct[3];
if (curr->type == INT_TYPE) {
int *pint = curr->data;
printf("int data = %d\n", *pint);
}

C Assign a string value to a string element in a struct using a function

I need to assign a string (char of size [255]) to an element in a struct. The struct looks like this:
struct node{
int ID, YEAR, MONTH, DAY
char CATEGORY[255], DETAIL[255];
double AMOUNT;
struct node * next;
}
struct node * head = NULL;
and I have code that gets values from a text file and sets it as a variable that I then pass to the add_struct function which looks like this:
void add_struct(int i, char c, char d, double a, int y, int m, int da){
if (head == NULL){
head = (struct node *) malloc(sizeof(struct node));
head->ID = i;
head->CATEGORY = c;
head->DETAIL = d;
head->AMOUNT = a;
head->YEAR = y;
head->MONTH = m;
head->DAY = da;
}
else {
struct node * p = head;
while(p->next != NULL) p = p->next;
p->next = (struct node *) malloc(sizeof(struct node));
p->next->ID = i;
p->next->CATEGORY = c;
p->next->DETAIL = d;
p->next->AMOUNT = a;
p->next->YEAR = y;
p->next->MONTH = m;
p->next->DAY = da;
}
}
I get error message:
"incompatible types when assigning to type 'char[255]' from type 'char'"
How do I assign these values to elements CATEGORY and DETAIL properly?
The CATEGORY and DETAIL field of the struct are defined as arrays of 255 chars, while c and d are variables of char. So you should change the function to void add_struct(int i, char *c, char *d, double a, int y, int m, int da), and copy the string to the allocated struct:
strcpy(head->CATEGORY, c);
strcpy(head->DETAIL, d);

How to assign values to a list in C

I have this list and I'm writing a function to ask the user to add the info:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXTAB 40
#define MAXSTR 25
typedef enum {Prob, Impr, Terr, Jail} Type;
typedef struct {
int pos;
char name[MAXSTR+1];
char owner[MAXSTR+1];
int price;
Type info;
} Casella;
struct lista {
Casella Tab;
struct lista *node;
};
typedef struct lista Lista;
void printElement (Lista *);
void printTab (Lista *);
Lista * initializeTab (Lista *, int);
Lista * addInfo (Lista*);
int main()
{
Lista *list = NULL;
int i;
for (i=0; i<MAXTAB; i++){
list = initializeTab(list, i);
}
printTab(list);
return 0;
}
void printElement (Lista *l){
printf("Position: %d\n", l->Tab.pos);
}
void printTab (Lista *l){
while(l!=NULL){
printElement(l);
l=l->node;
}
}
Lista * initializeTab (Lista *l, int x){
Lista *newTab = NULL;
newTab = (Lista*)malloc(sizeof(Lista));
newTab->Tab.pos = x;
newTab->node = l;
return newTab;
}
Lista * addInfo (Lista *l){
Lista *list = NULL;
list->Tab.name = (char*)malloc(MAXSTR * sizeof(char));
return list;
}`
In the function "addInfo", I try to allocate memory for the Tab name, but it tells me I can't assign type array char to that. My question is, how do I allocate memory for various list elements? Like I want to allocate memory for the list.name, then list.owner, list.pos etc... and then assign values to them.
In your structure definition
struct {
int pos;
char name[MAXSTR+1]; //array
char owner[MAXSTR+1]; //array
int price;
Type info;
} Casella;
name and owner are arrays, and they already have [MAXSTR+1] elements each. You don't need to allocate memory using malloc(). Just do strcpy().
Also, pos being an integer, simply assign the value using =. That should suffice.
Where you need to allocated memory is to list, which is a pointer. Something like
Lista *list = malloc(sizeof*list); //and a NULL check later
is required in first place.
Arrays in c are non-writeable lvalues, to achieve what you want you need to use a pointer instead, change the structure definition to this
typedef struct {
int pos;
char *name;
char *owner;
int price;
Type info;
} Casella;
Also, you malloc() and the pointer points to valid uninitialized memory so if you try to read from it undefined behavior will happen, try to change the addInfo() function to something like this
Lista *
addInfo (Lista *lista, const char *const name)
{
lista->Tab.name = strdup(name);
return lista;
}
Another very important mistake is that you set list to NULL inside addInfo() and then immediately dereference it, that is surely undefined behavior and the most likely outcome is that your program will crash.

All Nodes in a linked list point to same object

The problem is somewhere in here....
char buffer[80];
char *name;
while (1) {
fgets(buffer, 80, inf); //reads in at most 80 char from a line
if (feof(inf)) //this checks to see if the special EOF was read
break; //if so, break out of while and continue with your main
name = (char *) malloc(sizeof(char)*20);
....
name = strtok(buffer, " ");//get first token up to space
stock = newStock(name,...)
....
}
I'm working in C with generic linked lists. I made a list implementation that I've tested and know works with chars. I'm trying to add stocks (I created a stock struct) to the linked list, with each node of the linked list holding a stock struct, but when I finish reading in the stocks all of the nodes point to the same struct and I can't figure out why. Here's some snippets of my code
list *list = malloc(sizeof(list));
newList(list, sizeof(stock_t));
while(1) {
...
(read from file)
...
stock_t *stock;
stock = newStock(name, closes, opens, numshares, getPriceF, getTotalDollarAmountF,getPercentChangeF,toStringF);
addToBack(list, stock);
}
Here's the newStock function:
stock_t *newStock(char *name, float closingSharePrice, float openingSharePrice, int numberOfShares, getPrice getP, getTotalDollarAmount getTotal, getPercentChange getPercent, toString toStr) {
stock_t *stock = malloc(sizeof(stock));
stock->stockSymbol = name;
stock->closingSharePrice = closingSharePrice;
stock->openingSharePrice = openingSharePrice;
stock->numberOfShares = numberOfShares;
stock->getP = getP;
stock->getTotal = getTotal;
stock->getPercent = getPercent;
stock->toStr = toStr;
return stock;
}
In a way I see what's wrong. newStock returns a new pointer every time, but it always gets stored in the variable 'stock' which is what every node points to, so it's going to be equal to whatever the last pointer newStock returned was...but I don't see the way around this. I tried having newStock return just a stock_t, and doing addToBack(list, &stock), but that didn't solve the problem either.
Any help would be appreciated!
Here is some code from the list:
typedef struct node {
void *data;
struct node *next;
}node_t;
typedef struct {
int length;
int elementSize;
node_t *head;
node_t *tail;
} list;
void newList(list *list, int elementSize) {
assert(elementSize > 0);
list->length = 0;
list->elementSize = elementSize;
list->head = list->tail = NULL;
}
void addToBack(list *list, void *element) {
node_t *node = malloc(sizeof(node_t));
node->data = malloc(list->elementSize);
node->next = NULL; //back node
memcpy(node->data, element, list->elementSize);
if (list->length == 0) { //if first node added
list->head = list->tail = node;
}
else {
list->tail->next = node;
list->tail = node;
}
list->length++;
}
Here's code from the stock struct:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
typedef float (*getPrice)(void *S);
typedef float (*getTotalDollarAmount)(void *S);
typedef float (*getPercentChange)(void *S);
typedef char *(*toString)(void *S);
typedef struct stock{
char *stockSymbol;
float closingSharePrice;
float openingSharePrice;
int numberOfShares;
getPrice getP;
getTotalDollarAmount getTotal;
getPercentChange getPercent;
toString toStr;
}stock_t;
The generic functions probably seem like overkill but this is for homework (if you couldn't tell already) so we were asked to specifically use them. I don't think that has anything to do with the problem though.
Here are the definitions for those functions anyway
float getPriceF(void *S) {
stock_t *stock = (stock_t*)S;
return stock->closingSharePrice;
}
float getTotalDollarAmountF(void *S) {
stock_t *stock = (stock_t*)S;
return ((stock->closingSharePrice) * (stock->numberOfShares));
}
float getPercentChangeF(void *S) {
stock_t *stock = (stock_t*)S;
return ((stock->closingSharePrice - stock->openingSharePrice)/(stock->openingSharePrice));
}
char *toStringF(void *S) {
stock_t* stock = (stock_t*)S;
char *name = malloc(20*sizeof(char));
//sprintf(name, "Symbol is: %s. ", (stock->stockSymbol));
return stock->stockSymbol;
}
void printStock(void *S) {
char *str = toStringF(S);
printf("%s \n", str);
}
And this is how I'm traversing the list:
typedef void (*iterate)(void *); //this is in the list.h file, just putting it here to avoid confusion
void traverse(list *list, iterate iterator) {
assert(iterator != NULL);
node_t *current = list->head;
while (current != NULL) {
iterator(current->data);
current = current->next;
}
}
And then in my main I just called
traverse(list, printStock);
I can't find any problems with your code (that would cause your problem, anyway - there are places where you don't check the return from malloc() and stuff like that, but those are not relevant to this question). You don't supply the definition of stock_t, so I made a new data struct, and a new couple of functions, otherwise I just copied and pasted the code you provided:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
/* Your code starts here */
typedef struct node {
void *data;
struct node *next;
}node_t;
typedef struct {
int length;
int elementSize;
node_t *head;
node_t *tail;
} list;
void newList(list *list, int elementSize) {
assert(elementSize > 0);
list->length = 0;
list->elementSize = elementSize;
list->head = list->tail = NULL;
}
void addToBack(list *list, void *element) {
node_t *node = malloc(sizeof(node_t));
node->data = malloc(list->elementSize);
node->next = NULL; //back node
memcpy(node->data, element, list->elementSize);
if (list->length == 0) { //if first node added
list->head = list->tail = node;
}
else {
list->tail->next = node;
list->tail = node;
}
list->length++;
}
/* Your code ends here */
/* I made a new struct, rather than stock, since you didn't supply it */
struct mydata {
int num1;
int num2;
};
/* I use this instead of newStock(), but it works the same way */
struct mydata * newNode(const int a, const int b) {
struct mydata * newdata = malloc(sizeof *newdata);
if ( newdata == NULL ) {
fputs("Error allocating memory", stderr);
exit(EXIT_FAILURE);
}
newdata->num1 = a;
newdata->num2 = b;
return newdata;
}
/* I added this function to check the list is good */
void printList(list * list) {
struct node * node = list->head;
int n = 1;
while ( node ) {
struct mydata * data = node->data;
printf("%d: %d %d\n", n++, data->num1, data->num2);
node = node->next;
}
}
/* Main function */
int main(void) {
list *list = malloc(sizeof(list));
newList(list, sizeof(struct mydata));
struct mydata * data;
data = newNode(1, 2);
addToBack(list, data);
data = newNode(3, 4);
addToBack(list, data);
data = newNode(5, 6);
addToBack(list, data);
printList(list);
return 0;
}
which outputs this:
paul#MacBook:~/Documents/src$ ./list
1: 1 2
2: 3 4
3: 5 6
paul#MacBook:~/Documents/src$
demonstrating that you have a 3 node list, with all nodes different and where you'd expect them to be.
Either there is some other problem in code you're not showing, or for some reason you are thinking each node points to the same struct when it actually doesn't.
One possibility is that you have a char * data member in your stock struct. It's impossible to tell from the code you provided, but it's possible that you really are creating different nodes, but they all end up pointing to the same name, so they just look like they're the same. If you're assigning a pointer to name, you should make sure it's freshly allocated memory each time, and that you're not just, for instance, strcpy()ing into the same memory and assigning the same address to each stock struct.
EDIT: Looks like that was your problem. This:
name = (char *) malloc(sizeof(char)*20);
....
name = strtok(buffer, " ");
should be:
name = (char *) malloc(sizeof(char)*20);
....
strcpy(name, strtok(buffer, " "));
Right now, you malloc() new memory and store a reference to it in name, but then you lose that reference and your memory when you overwrite it with the address returned from strtok(). Instead, you need to copy that token into your newly allocated memory, as shown.

Structure Link List Segmentation-Fault

I just got started on a lab of mine where I calculate the GPA of courses whose information is stored in a linked list of structures. As of now, I'm attempting to just print out all the course information to ensure that they have been properly initialized and added to the link list.
I'm running into a problem though because I keep getting a Segmentation Fault. I understand what the Segmentation Fault means, but I do not know where I am making my mistake. Any help would be appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#define MAX_CLASSES 20
/* Function Prototypes */
struct course * initcourse( int, char *, char *, float, char *, char *);
void add( struct course * );
/* Definition of a data node holding course information */
struct course {
int term;
char name[15];
char abbrev[20];
float hours;
char grade [4];
char type[12];
struct course *next;
};
/* head points to first node in list, end points to last node in list */
/* initializes both to NULL, no nodes yet */
struct course *head = (struct course *) NULL;
struct course *end = (struct course *) NULL;
/* Initializes a node, allocates memory for the node, and returns */
/* a pointer to the new node. Must pass correct parameters. */
struct course * initcourse( int term, char *name, char *abbrev, float hours, char *grade, char *type)
{
struct course *ptr;
ptr = (struct course *) calloc( 1, sizeof(struct course ) );
if( ptr == NULL )
return (struct course *) NULL;
else
{
ptr->term = term;
strcpy( ptr->name, name );
strcpy( ptr->abbrev, abbrev );
ptr->hours = hours;
strcpy( ptr->grade, grade );
strcpy( ptr->type, type );
return ptr;
}
}
/* This adds a node to the end of the list. You must allocate a node and */
/* then pass its address to this function */
void add(struct course *new)
{
if (head == NULL)
{
head = new;
}
else
{
end->next = new;
end = new;
}
}
/* Prints all information in a node */
void printnode( struct course *ptr )
{
printf("Term ->%d\n", ptr->term );
printf("Name ->%s\n", ptr->name );
printf("Abbreviation ->%s\n", ptr->abbrev );
printf("Hours ->%f\n", ptr->hours );
printf("Grade ->%s\n", ptr->grade );
printf("Type ->%s\n", ptr->type );
}
/* Prints List of Nodes */
void printlist( struct course *ptr )
{
while( ptr != NULL )
{
printnode( ptr );
ptr = ptr->next;
}
}
/* Calculates GPA */
/* float gpa ( struct course *ptr ) */
/* { */
/* float totalhours; */
/* float gpa; */
/* float gradepoints; */
/* while (ptr != NULL ) */
/* { */
/* totalhours += (ptr->hours); */
/* gradepoints = (ptr->hours * ptr->grade); */
/* } */
/* gpa = (gradepoints /ptr->hours); */
/* } */
int main()
{
int term;
char name[15];
char abbrev[20];
float hours;
char grade[4];
char type[12];
float gpa;
struct course *ptr;
struct course course1, course2, course3;
course1.term = 1234;
strcpy(course1.name,"cse1234");
strcpy(course1.abbrev,"systems");
course1.hours = 4;
strcpy(course1.grade,"A");
strcpy(course1.type,"GEC");
ptr = initcourse(course1.term, course1.name, course1.abbrev, course1.hours, course1.grade, course1.type);
struct course *head, *ptr2;
head = ptr;
// ptr2 = ptr;
add(ptr);
course2.term = 4332;
strcpy(course2.name,"cse4332");
strcpy(course2.abbrev,"Database");
course2.hours = 4;
strcpy(course2.grade,"B");
strcpy(course2.type,"Technical");
ptr2 = initcourse(course2.term, course2.name, course2.abbrev, course2.hours, course2.grade, course2.type);
add(ptr2);
printlist(head);
}
void add(struct course *new)
{
if (head == NULL)
{
head = new;
}
else
{
end->next = new;
end = new;
}
}
You need to set end to new when inserting the first node (when head == NULL), otherwise you're dereferencing a null-pointer when adding further nodes.
And in initcourse, you ought to set the next member to NULL, since it is not guaranteed by the standard that all-bits-0 is a null-pointer representation (it very likely is, but there's no guarantee).
Also,
struct course *head, *ptr2;
head = ptr;
declares a new local variable head that shadows the global one, and instead of assigning directly to head (even though it's the wrong one), you should call add(ptr);.
You dont initialize the next pointer, so the last element contains a bad pointer, pointing to some garbage.
You also don't initialize end.
Another problem (not related to the crash) is that this code will create a duplicate entry:
head = ptr;
add(ptr);
There're other problems. You really should get a debugger and see what's going on.

Resources