I am experiencing problems on linked list with pointer variables inside the struct. Everytime when i insert a new visitor data, the previous visitors data will all be changed to the most current visitor data.
struct visitData{
char *SrNo;
char *ticketNo;
char *Name;
char *ID;
};
typedef struct ticket {
struct visitData visitor;
struct ticket *nextPtr;
}tick;
tick *addinfo(tick *previous,char* serial,char* ticketno,char* name,char* id)
{
tick *info = malloc(sizeof(tick));
info->nextPtr = NULL;
info->visitor.SrNo =serial;
info->visitor.ticketNo = ticketno;
info->visitor.Name = name;
info->visitor.ID=id;
if (previous != NULL)
{
previous->nextPtr = info;
}
printf("visitor info has been added: %s %s %s %s",info->visitor.SrNo,info->visitor.ticketNo,info->visitor.Name,info->visitor.ID);
return info;
}
This should work:
#include <string.h>
tick *addinfo(tick *previous,char* serial,char* ticketno,char* name,char* id)
{
tick *info = malloc(sizeof(tick));
info->nextPtr = NULL;
info->visitor.SrNo = strdup(serial);
info->visitor.ticketNo = strdup(ticketno);
info->visitor.Name = strdup(name);
info->visitor.ID=strdup(id);
if (previous != NULL)
{
previous->nextPtr = info;
}
printf("visitor info has been added: %s %s %s %s \n",info->visitor.SrNo,info->visitor.ticketNo,info->visitor.Name,info->visitor.ID);
return info;
}
The problem was that you weren't allocating memory for your data.
Also, be sure to free it when the program ends.
Related
I am attempting to create a linked list from a file using structs, when I run the print_list it is not printing the name or threat level, but it is printing the ID. I have little experience with structs but I believe I am not understanding if the pointers are being used correctly here.
void insert(struct poi_t_struct **head_ref, char *name, long int id, int threat_level) {
// printf("Name from insert %s \n", name); // debug
struct poi_t_struct newNode = { name, id, threat_level, NULL };
struct poi_t_struct *ptr_newNode = &newNode;
struct poi_t_struct *temp = *head_ref;
}
void buildLList(char *filename) {
FILE *poiProfiles;
// char line[MAX_LINE_LENGTH];
// have 3 char arrays. One for each name, id, threat level
char idLine[MAX_LINE_LENGTH];
char nameLine[MAX_LINE_LENGTH];
char threat_levelLine[MAX_LINE_LENGTH];
while (fgets(idLine, MAX_LINE_LENGTH, poiProfiles)) {
long int id;
id = atoi(idLine);
fgets(nameLine, MAX_LINE_LENGTH, poiProfiles);
char* name;
name = nameLine;
fgets(threat_levelLine, MAX_LINE_LENGTH, poiProfiles);
int threat_level;
threat_level = atoi(threat_levelLine);
insert(&head, name, id, threat_level);
}
void print_list(struct poi_t_struct *p) {
struct poi_t_struct *temp = p;
while (temp != NULL) {
print_record(temp);
temp = temp->next;
}
}
There are multiple problems in your code:
you do not open nor close the file for poiProfiles
there is a missing } at the end of the buildLList() function.
the insert function must allocate memory for the new node, inserting a local struct object is incorrect as this object becomes invalid as soon as the function returns. You attempt to insert the new node at the beginning of the list, but you neither set the next member of the struct, not set *head_ref to point to the new node.
Here is a modified version:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct poi_t_struct {
char *name;
long int id;
int threat_level;
struct poi_t_struct *next;
} *head;
int insert(struct poi_t_struct **head_ref, const char *name, long int id, int threat_level) {
// printf("Name from insert %s \n", name); // debug
struct poi_t_struct *ptr_newNode = malloc(sizeof *ptr_newNode);
if (ptr_newNode == NULL)
return -1;
ptr_newNode->name = strdup(name);
ptr_newNode->id = id;
ptr_newNode->threat_level = threat_level;
ptr_newNode->next = *head_ref;
*head_ref = ptr_newNode;
return 0;
}
int buildLList(const char *filename) {
// have 3 char arrays. One for each name, id, threat level
char idLine[MAX_LINE_LENGTH];
char nameLine[MAX_LINE_LENGTH];
char threat_levelLine[MAX_LINE_LENGTH];
FILE *poiProfiles;
int count = 0;
poiProfiles = fopen(filename, "r");
if (poiProfiles == NULL) {
fprintf(stderr, "cannot open %s: %s\n", filename, strerror(errno));
return -1;
}
while (fgets(idLine, MAX_LINE_LENGTH, poiProfiles)
&& fgets(nameLine, MAX_LINE_LENGTH, poiProfiles)
&& fgets(threat_levelLine, MAX_LINE_LENGTH, poiProfiles)) {
long int id = atoi(idLine);
char *name = nameLine;
int threat_level = atoi(threat_levelLine);
if (!insert(&head, name, id, threat_level))
count++;
}
fclose(poiProfiles);
return count;
}
void print_list(const struct poi_t_struct *p) {
const struct poi_t_struct *temp = p;
while (temp != NULL) {
print_record(temp);
temp = temp->next;
}
}
I'm trying to use tasklist and pipe the output to my code and parse each line to then create nodes of every process. I will later be filtering through them but that is not in the code yet. I'm having problems with the LIST. I have implemented 3 structs for this program: LIST (head for first node, rear for last node and count for number of nodes in list), NODE (pointer to PROCESS_INFO and pointer to next NODE), PROCESS_INFO (4 char pointers for process name, PID, memory usage and cputime). I've used printf to track my code and everything seems to work properly until I get to adding them to the linked list. The address of each nodes are different but it always seems to overwrite the last one in the list instead of adding the new address of the node to the next* of the previous node.
I'm mostly positive my algorithm is correct, it's the same one I've used multiple times just with different data. My malloc functions have dynamic checks incase they fault and I've checked and played with my pointers incase I was missing a dereference of some sort but I get errors if I change anything so I don't think those are the problem funny enough.
The only thing I can think of that would be the problem is the fact that all this doing resides in a loop in a function (I read somewhere that pointers on a stack can't remember their address?). What would I have to change though to fix this? I've moved everything to main but nothing changed.
Struct Definitions:
typedef struct processInfo{
char *pName;
char *processId;
char *memUsage;
char *cpuTime;
}PROCESS_INFO;
typedef struct node{
PROCESS_INFO* data;
struct node* next;
}NODE;
typedef struct li{
int num;
NODE* head;
NODE* rear;
}LIST;
Main function:
int main()
{
LIST* list;
list = buildList();
printList(list);
}
List functions:
//function that creates a new list and returns it as null
LIST* createList()
{
LIST* newListPtr;
newListPtr = (LIST*)malloc(sizeof(LIST));
if (newListPtr)
{
newListPtr->num = 0;
newListPtr->head = NULL;
newListPtr->rear = NULL;
}
return newListPtr;
}
//function that creates the struct for the information of the process
PROCESS_INFO* createPinfo(char* name, char* pid, char* kb, char* cTime)
{
PROCESS_INFO* pInfoPtr;
pInfoPtr = (PROCESS_INFO*)malloc(sizeof(PROCESS_INFO));
if (pInfoPtr)
{
pInfoPtr->pName = name;
pInfoPtr->processId = pid;
pInfoPtr->memUsage = kb;
pInfoPtr->cpuTime = cTime;
}
return pInfoPtr;
}
//function to create new node and set its data
NODE* createNode(PROCESS_INFO* dataPtr)
{
NODE* nodePtr;
nodePtr = (NODE*)malloc(sizeof(NODE));
if (nodePtr)
{
nodePtr->data = dataPtr;
nodePtr->next = NULL;
}
return nodePtr;
}
//Get process information node via the path
PROCESS_INFO* parseInfoFromPath (char str[])
{
char *pName;
char *processId;
char *memUsage;
char *time;
char *parse;
parse = strtok(str, " ");
pName = parse;
parse = strtok(NULL, " ");
processId = parse;
parse = strtok(NULL, " "); //Console
parse = strtok(NULL, " "); //session
parse = strtok(NULL, " "); //memory
memUsage = parse;
parse = strtok(NULL, " ");
parse = strtok(NULL, " ");
parse = strtok(NULL, " ");
parse = strtok(NULL, " "); //CPUTIME
time = parse;
PROCESS_INFO* pInfoPtr;
pInfoPtr = createPinfo(pName, processId, memUsage, time);
return pInfoPtr;
}
BuildList() function where I seem to be getting the semantic error:
LIST* buildList()
{
FILE *fp;
char path[PATH_MAX];
fp = popen("tasklist /v /fi \"STATUS eq running\" /nh ", "r");
if (fp == NULL)
{
printf( "CreateProcess failed (%d).\n", GetLastError() );
return;
}
LIST* list_;
PROCESS_INFO* p;
NODE* n;
list_ = createList();
while (fgets(path, PATH_MAX, fp) != NULL)
{
if (path != NULL)
{
//create the process info struct
p = parseInfoFromPath(path);
//create the node
n = createNode(p);
//add node to list
//if empty list set as head
if (list_->head == NULL){
list_->head = n;
}
//otherwise set last->next to point to the new node
else {
list_->rear->next = n;
}
//rear points to last node
list_->rear = n;
(list_->num)++;
}
}
//They always print out the same data!!!!
printf("\nIn Loop: Head Node name: %s", list_->head->data->pName);
printf("\t\tIn Loop: Read Node name: %s", list_->rear->data->pName);
return list_;
}
You are not copying the strings for each input field you find. Instead you are holding pointers into your path buffer, which gets overwritten every time you do fgets. Try using strdup in createPinfo:
PROCESS_INFO* createPinfo(char* name, char* pid, char* kb, char* cTime)
{
PROCESS_INFO* pInfoPtr;
pInfoPtr = (PROCESS_INFO*)malloc(sizeof(PROCESS_INFO));
if (pInfoPtr)
{
pInfoPtr->pName = strdup(name);
pInfoPtr->processId = strdup(pid);
pInfoPtr->memUsage = strdup(kb);
pInfoPtr->cpuTime = strdup(cTime);
}
return pInfoPtr;
}
Also, since strdup allocates heap memory, don't forget to add a function to free the memory and call it every time you remove something from the list. Eg:
void destroyPinfo(PROCESS_INFO* pInfoPtr)
{
if (pInfoPtr)
{
free(pInfoPtr->pName);
pInfoPtr->pName = NULL;
free(pInfoPtr->processId);
pInfoPtr->processId = NULL;
free(pInfoPtr->memUsage);
pInfoPtr->memUsage = NULL;
free(pInfoPtr->cpuTime);
pInfoPtr->cpuTime = NULL;
}
}
You will probably want to NULL check the results of strdup like you do malloc (I'm too lazy to add this in to the answer though, as long as you get the basic idea).
As my current function stands I can only read the first set of data from a file. I am sure that it is because of the !feof not functioning the way I want it to but it might also be caused by a bad print list function but I am not to sure. I am pretty much brand new to using dynamic memory so bear with me.
Load from File
void load(FILE *file, Node *head)
{
char tempArtist[30] = {'\0'}, tempAlbum[30] = {'\0'}, tempTitle[30] = {'\0'}, tempGenre[30] = {'\0'}, tempSpace = '\0';
SongLength *tempLength = NULL;
char tempPlay[100] = {'\0'}, tempRating[6] = {'\0'}, tempMins[3] = {'\0'}, tempSecs[3] = {'\0'};
tempLength = (SongLength *)malloc(sizeof(SongLength));
while (!feof(file))
{
while (head->pNext == NULL) // Here is where I need to shift to the next node
{
fscanf(file, "%s", &tempArtist);
fscanf(file, "%c", &tempSpace);
strcpy(tempLength->mins, tempMins);
strcpy(tempLength->secs, tempSecs);
strcpy(head->data->artist, tempArtist);
strcpy(head->data->length->mins, tempLength->mins);
strcpy(head->data->length->secs, tempLength->secs);
insertNode(head, head->data);
}
}
free(tempLength);
}
Insert to linked list
void insertNode(Node *head, Record *data)
{
while(head->pNext == NULL)
{
head=head->pNext;
}
head->pNext=(Node*)malloc(sizeof(Node));
head->pNext->data = (Record*)malloc(sizeof(Record));
head->pNext->data->length=(SongLength*)malloc(sizeof(SongLength));
(head->pNext)->pPrev=head;
head=head->pNext;
head->data=data;
head->pNext=NULL;
}
Print all of the data in the list(hopefully)
void display (Node *head)
{
while (head->pNext != NULL)
{
printf ("Artist: %s\n", head->data->artist);
printf ("Length(mm:ss) %s:%s\n", head->data->length->mins,head->data->length->secs);
head=head->pNext;
}
putchar ('\n');
}
I have removed all but one of the fscanf()'s and printf()'s to cut down the code.
Structs
typedef struct songlength
{
char mins[3];
char secs[3];
}SongLength;
typedef struct record
{
char artist[30];
struct songlength *length;
}Record;
typedef struct node
{
struct node *pPrev;
struct record *data;
struct node *pNext;
}Node;
the function call insertNode(head,head->data); looks strange. The second argument have to be data not from the head, otherwise data in head is rewritten for any new record.
So allocate memory for Record inside load function and do not use head->data.
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.
I want to write a server/client program using RPC which transfers a struct from a client (containing some strings) to the server. This struct has to be saved on the server using a linked list. At this moment, I have the following code:
.x-file:
struct paper_node
{
long id;
string author<>;
struct paper_node *next;
};
struct add_in
{
string author<>;
};
typedef struct paper_node *list_node;
server
add_out *add_proc_1_svc(add_in *in, struct svc_req *rqstp)
{
static add_out out;
static long id = 1;
static paper_node *list = NULL;
//paper_node *p, *q;
paper_node *pointer, *new_paper;
new_paper = (paper_node *) malloc(sizeof(paper_node));
new_paper->id = id;
new_paper->author = in->author;
new_paper->next = NULL;
if (list == NULL)
{
list = new_paper;
}
else
{
for (pointer = list; pointer->next != NULL; pointer = pointer->next);
pointer->next = new_paper;
}
printf("%ld - %s\n", list->id, (char *)list->author);
out = id;
id += 1;
return(&out);
}
client
void handle_new_paper(char **argv, CLIENT *cl)
{
add_in in;
add_out *out;
buffer = read_new_paper(argv);
in.author = argv[3];
out = add_proc_1(&in, cl);
if (out == NULL) { printf("Error: %s\n", clnt_sperror(cl, argv[1])); }
else
{
printf("%ld\n", *out);
}
free(buffer);
}
The server doesn't seem to add the strings to the list correctly. When printing the list-id (head of the list) it does print '1' every time, but it just prints the string-values that were given to the server-function at the current call (and not the string-values of the first item in the list).
Anybody knows where this goes wrong?
I'm just guessing here, but it might be that the RPC implementation reuses the string buffer used, so in->author always points to the same buffer?
You can easily find that out by printing the address of in->author for every request.