Adding an element to a struct that contains a char pointer - c

Okay so I am sure this is not too difficult a question but I am lost after trying to figure it out for so long so here is the code first the declaration for my structs.
struct GraphicElement {
char* fileName;
struct GraphicElement* pNext;
};
struct RasterGraphic {
struct GraphicElement* GraphicElements;
};
Then I call a function that takes care of the initialization which I believe is working properly.
int main(void)
{
char response;
BOOL RUNNING = TRUE;
struct RasterGraphic RG;
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
InitRasterGraphic(&RG);
The init function is as follows
void InitRasterGraphic(struct RasterGraphic* pA)
{
pA->GraphicElements = malloc(sizeof(struct GraphicElement));
if (pA->GraphicElements == NULL) return;
//pA->GraphicElements = 0;
//pA->GraphicElements->pNext = NULL;
//pA->GraphicElements->fileName = NULL;
pA->GraphicElements->fileName = (char*)malloc(sizeof(char));
return;
}
So the next part of code is where I am going to ask my question. I have a function that takes a user input of some sort of string. Id like to take that input and add it to the next element. So every time the user calls the function they put in their input and its added to the next element. My code right now is a mess and I know it definitely is probably way off I've tried a bunch of things already. I believe I need to use realloc. What I am not able to wrap my head around here is how to take the input and add it so that later on I can printf all the elements in order. so for example user calls function 3 times and puts in inputs "hello" "world". Later I would like to cycle through and print
graphic 1 is "hello"
graphic 2 is "world"
void InsertGraphicElement(struct RasterGraphic* pA)
{
char response[256];
printf("Insert a GraphicElement in the RasterGraphic\nPlease enter the GraphicElement filename: ");
scanf("%s", &response[0]);
pA->GraphicElements->fileName = realloc(pA->GraphicElements, 256*sizeof(char));
pA->GraphicElements++;
strcpy(pA->GraphicElements->fileName, &response);
if (pA->GraphicElements == 1){
printf("\nThis is the first GraphicElement in the list\n");
}
return;
}

Here are the few issues in your code.
I believe InitRasterGraphic should just initialize the pA->GraphicElements = NULL instead of mallocing it. Since same should be handled in InsertGraphicElement function.
pA->GraphicElements->fileName = (char*)malloc(sizeof(char)); this will just allocate the memory of size single char and there is no point in allocing and reallocing.
scanf("%s", &response[0]); should be scanf("%s", &response[0]);.
pA->GraphicElements++; This is wrong instead use one more member to maintain the number of nodes in the list.
Hence after correcting the above issues your code will look like below.
your RasterGraphic will look like below.
struct RasterGraphic {
int numNodes;
struct GraphicElement* GraphicElements;
};
Your InitRasterGraphic will look like below.
void InitRasterGraphic(struct RasterGraphic* pA)
{
pA->GraphicElements = NULL;
pA->numNodes = 0;
return;
}
Your InsertGraphicElement will look like below.
void InsertGraphicElement(struct RasterGraphic* pA)
{
struct GraphicElement *newNode = malloc(sizeof(*newNode));
if (newNode == NULL) return;
newNode->fileName = malloc(256*sizeof(char));
if (newNode->fileName == NULL) return;
newNode->pNext = NULL;
printf("Insert a GraphicElement in the RasterGraphic\nPlease enter the GraphicElement filename: ");
scanf("%s", newNode->fileName);
if (pA->GraphicElements == NULL)
{
pA->GraphicElements = newNode;
}
else
{
struct GraphicElement *tempHead = pA->GraphicElements;
while(tempHead->pNext != NULL)
{
tempHead = tempHead->pNext;
}
tempHead->pNext = newNode;
}
pA->numNodes++;
if (pA->numNodes == 1){
printf("\nThis is the first GraphicElement in the list\n");
}
return;
}

Related

Add words received from the user to the linked-list in C programming

#include <stdio.h>
#include <stdlib.h>
struct node {
char *str;
struct node *next;
};
struct node *start = NULL;
struct node *temp = NULL;
struct node *q = NULL;
void sonaEkle(char *veri) {
struct node *eklenecek = (struct node *)malloc(sizeof(struct node));
eklenecek->str = veri;
eklenecek->next = NULL;
if (start == NULL) {
start = eklenecek;
} else {
q = start;
while (q->next != NULL) {
q = q->next;
}
}
}
void yazdir() {
q = start;
while (q->next != NULL) {
printf("%s", q->str);
q = q->next;
}
printf("%s", q->str);
}
int main() {
char *veri;
while (1 == 1) {
printf("enter string");
scanf("%s", veri);
sonaEkle(veri);
yazdir();
}
return 0;
}
I have created a Linked list.
This linked list adds the string it received from the user to the end. But my code is giving a loop error. How can I fix this?
for example: user input:abc bcd cde
output:abc => bcd => cde
This is an infinite loop
while(1 == 1) {
printf("enter string");
scanf("%s",veri);
sonaEkle(veri);
yazdir();
}
Rewrite it in this way
while( puts("enter string") && scanf("%s",veri) == 1 ) {
sonaEkle(veri);
yazdir();
}
And also you need to allocate memory for veri before you can use it in scanf. But you could as well just making it an array.
char veri[SIZE];
There are multiple problems with the code
char *veri;
while(1 == 1){
First statement veri needs memory, since it is a pointer, you need some thing like this veri = malloc(somesize);
Second statement is an infinite loop, you need some termination point, better use something like below to break the infinite loop.
while(1){
// after malloc
scanf("%s",veri);
//enter exit whenever you want to exit from program.
if(strcmp(veri,"exit") == 0)
break;
Function sonaEkle you are allocating memory for struct node* , but you are not returning updated nodes address start
you need to have sonaEkle like this struct node* sonaEkle(char *veri) and return start after every update and no need to cast malloc.
4)
else {
q=start;
while(q->next != NULL) {
q=q->next;
}
The above part just iterates list, you need to add new nodes to q->next when it reaches to NULL and return start afterwards in order to have next elements in the list.
Correct all those problems , to make you program work.
NOTE:
check the pointers for NULL after every malloc
free the malloc'ed memory once you are done with your program.

add a struct into struct linked list in C

I need to write software that gets structure from the user (name, path and time) and then add the structure to the end of a linked list. I wrote two functions that work the problem that it only works in the first run, if the user tries to add another structure to the linked program the program crashes):
Can anyone help me understand what the problem is?
Thank you!
These are the structures I created:
// Frame struct
typedef struct Frame
{
char* name;
int duration;
char* path;
} Frame;
// Link (node) struct
typedef struct FrameNode
{
Frame* frame;
struct FrameNode* next;
} FrameNode;
What are the functions:
FrameNode* addFrame(Frame frame)
{
FrameNode* p = malloc(sizeof frame);
printf("*** Creating a new frame ***\n");
printf("Please insert frame path:\n");
p->frame->path = (char*)malloc(sizeof(char*) * 100);
fgets(p->frame->path, 100, stdin);
p->frame->path[strcspn(p->frame->path, "\n")] = 0;
printf("Please insert frame duration <in miliseconds>:\n");
scanf_s("%d", &(p->frame->duration));
getchar();
printf("Please chooce a name for a new frame:\n");
p->frame->name = (char*)malloc(sizeof(char*) * 100);
fgets(p->frame->name, 100, stdin);
p->frame->name[strcspn(p->frame->name, "\n")] = 0;
while (list != NULL)
{
while (strcmp(list->frame->name, p->frame->name) == 0)
{
printf("The name is already taken, Please enter another name\n");
fgets(p->frame->name, 100, stdin);
}
}
p->next = NULL;
return p;
}
FrameNode* insertAtEnd(FrameNode* list, Frame fr)
{
FrameNode* tmp = addFrame(fr);
if (list != NULL)
{
list = list->next;
}
list = tmp;
return list;
}
The problem is here-
if (list != NULL)
{
list = list->next;
}
list = tmp;
Correct one is
while(list>next != NULL)
{
list = list->next;
}
list->next = tmp;
This will go to next until the last frame and add the new frame. In your code, it works first time because it only executes list=tmp. For other times, we are not going to the end of the list to add tmp. Note if instead of while.
Also, in your code when list becomes NULL, we lose address of last frame, so we need the loop till list>next!=NULL instead of list!=NULL.

Address of nodes keep overwriting each other when being added to linked list

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).

adding a node to a linked list using a function

I currently have a linked list and need to add data to it that is inputted by the user from the keyboard so i have two structs:
struct CourseInfo {
int courseID;
char courseName[30];
};
typedef struct CourseInfo courseinfo;
struct StudentInfo {
char StudentID[10];
char FirstName[21];
char LastName[26];
int num_course;
courseinfo array[10];
struct StudentInfo *next;
};
So i have a linked list with 3 nodes currently. I then need to call a function and add a node. The node needs to be inserted in the correct place which is that the studentID before it needs to be less than it and the studentID after needs to be greater so the current IDs i have are 111111111, 333333333, and 444444444 and im trying to add 222222222 so it would go in the second spot so my function looks like:
studentinfo *addStudent(studentinfo *data) //returns type studentinfo* now
{
studentinfo *add;
add = malloc(sizeof(studentinfo));
add->next = NULL; //Now its set to NULL to begin
int knt;
printf("%s", "Adding new student:\nStudent ID: ");
scanf("%s", add->StudentID);
printf("%s", "First Name: ");
scanf("%s", add->FirstName);
printf("%s", "Last Name: ");
scanf("%s", add->LastName);
printf("%s", "Number of courses: ");
scanf("%d", &add->num_course);
for(knt = 0; knt < add->num_course; knt++) {
printf("%s", "Course ID: ");
scanf("%d", &add->array[knt].courseID);
printf("%s", "Course Name: ");
scanf("%s", add->array[knt].courseName);
}
if(searchStudentID(data, add->StudentID)) {
puts("immediately inside if");
while(data != NULL) {
puts("Immediately inside while");
if(strcmp(add->StudentID, data->StudentID) < 0) {
puts("inside if");
add->next = data;
data = add;
}
else {
puts("inside first else");
studentinfo *PrevPtr = data;
studentinfo *NPtr = data->next;
while(NPtr != NULL) {
("inside while(NPTR != NULL)");
if(strcmp(add->StudentID, NPtr->StudentID) < 0) {
add->next = PrevPtr;
PrevPtr->next = add;
break;
}
else {
puts("inside a differnet else");
PrevPtr = NPtr;
NPtr = NPtr->next;
}
}
if(PrevPtr->next == NULL) {
puts("inside last if");
add->next = NULL;
PrevPtr->next = add;
}
}
}
}
else {
puts("Found id");
}
return data; //returns data back to call
}
So i added all those puts statement because i wanted to see why the program kept crashing. So the puts statement puts("Inside a different else") is stuck in an infinite loop and keeps printing. The function searchStudentID simply returns 1 if we dont already have the ID and 0 if we already have it. I know that this function works so there is no need to post it.
I think the problem may be in the break; statement because it doesnt exit from the first while loop but only exits from the inner loop but im not positive.The call to this function look like:
list = addStudent(list); //Now the new data is stored in list
Where list is the linked list with 3 nodes
Linked list management is about managing node pointers, not just nodes. You want to do several things to make this considerably easier on yourself:
Separate the input step from the search+insertion step. They don't belong together regardless of how they may seem otherwise. The biggest benefit this brings to you is reducing your list insertion code to what it should be doing (and only what it should be doing): managing the linked list. I've kept yours intact, but you should really be error checking and doing the data reading somewhere else.
Use a pointer to pointer to walk the list. The biggest benefit from this is eliminating the need to special-case head-position insertion. If that is the position a new node will eventually occupy, so be it, but eliminating that special-case further reduces the complexity of the algorithm.
Don't search the list unless you're capable of retaining the search results to be used for insertion logic. It makes little sense to perform an O(N) scan of the linked list to determine if input data is already present, only to search it again to find the position said-data will actually be inserted. Do it once. Find the position where it belongs. If it is already there, do nothing, otherwise, you sit at the precipice of the proper insertion location already.
Finally, don't allocate a new node unless you know you need one. Use an automatic variable that helpfully self-discards if you end up doing nothing.
Putting all of that together gives something like this:
struct CourseInfo {
int courseID;
char courseName[30];
};
typedef struct CourseInfo CourseInfo;
struct StudentInfo {
char StudentID[10];
char FirstName[21];
char LastName[26];
int num_course;
CourseInfo array[10];
struct StudentInfo *next;
};
typedef struct StudentInfo StudentInfo;
StudentInfo *addStudent(StudentInfo *head)
{
StudentInfo **pp = &head, *p = NULL, rec;
int knt;
// TODO: error check your inputs!
printf("%s", "Adding new student:\nStudent ID: ");
scanf("%s", rec.StudentID);
printf("%s", "First Name: ");
scanf("%s", rec.FirstName);
printf("%s", "Last Name: ");
scanf("%s", rec.LastName);
printf("%s", "Number of courses: ");
scanf("%d", &rec.num_course);
for(knt = 0; knt < rec.num_course; knt++) {
printf("%s", "Course ID: ");
scanf("%d", &rec.array[knt].courseID);
printf("%s", "Course Name: ");
scanf("%s", rec.array[knt].courseName);
}
// walk the list pointers, starting with head, looking for
// a node that is equal or greater than the input node
while (*pp && (knt = strcmp((*pp)->StudentID, rec.StudentID)) < 0)
pp = &(*pp)->next;
// leave now if already present
if (*pp && knt == 0)
return head;
// allocate new node
p = malloc(sizeof *p);
if (p == NULL)
{
perror("Failed to allocate new node");
exit(EXIT_FAILURE);
}
// structure copy.
*p = rec;
// link into proper list position.
p->next = *pp;
*pp = p;
// always return the head (which may have updated above)
return head;
}
That's it. As mentioned, I would personally perform the input operation somewhere other than this function, but I leave that to you to consider.
Best of luck.
Since this function updates the list you either need it to be
studentinfo *addStudent(studentifo *data)
and return the updated head value. Or
void addStudent(studentifo **data)
and do
*data = <new thing>
Issues that I see:
You are not setting add->next to NULL.
You are changing data locally.
add->next = data;
data = add;
changes the value of data locally in the function. It does not change the value in the calling function.
You have the check
while(data != NULL)
following the if statement
if(searchStudentID(data, add->StudentID)) {
but I don't see any code to add the new student when searchStudentID(data, add->StudentID) returns false and when data == NULL to start with.

C, Printing more than one integer from a linked list

I'm very new to C, so I'm not totally sure what's the matter. I can't figure out how to print more than a single integer value in a function.
add function:
void add(char *name,int id,int copies)
{
/* Pointer to next item */
struct list *newAlbum;
newAlbum = malloc(sizeof(struct list));
strcpy((*newAlbum).name, name); // Set album name
newAlbum->id = id;
newAlbum->copies = copies;
newAlbum->pNext = pFirst;
pFirst = newAlbum;
}
show function:
void show()
{
system("clear");
struct list *current_node;
current_node = pFirst;
while(current_node != NULL)
{
printf("Album #%d \n",current_node->id);
printf("Album Name: %s \n",current_node->name);
printf("Album Copies:%d \n",current_node->copies);
printf("\n");
current_node=current_node->pNext;
}
}
My program prints out the current_node->id as if it were current_node->copies, and current_node->copies is printed out as 134516043, which is obviously, wrong.
I think I must be passing something wrong to the function or something, but I can't figure it out. Any tips?
I call the function add like this:
add(name,id,copies);
The list is as so:
/* THE LIST */
struct list{
char name[52];
int id;
int copies;
int sold;
struct list* pNext;
};
struct list *pFirst = NULL;
I call the function with user input with this piece of code:
printf("Enter the name of the new album. \n");
scanf("%s",&name);
printf("Enter the album id. \n");
scanf("%d",&id);
printf("Enter number of copies. \n");
scanf("%d," &copies);
// Pass data to add()
add(name,id,copies);
Your code that you've shown is OK, as long as you don't pass an album name to add() which is longer than 51 characters. If you do, you'll get very weird output, and possibly a crash.
To guard against this, you should use a length-limited copy - for example:
void add(char *name,int id,int copies)
{
/* Pointer to next item */
struct list *newAlbum;
newAlbum = malloc(sizeof *newAlbum);
if (newAlbum) {
snprintf(newAlbum->name, sizeof newAlbum->name, "%s", name); // Set album name
newAlbum->id = id;
newAlbum->copies = copies;
newAlbum->pNext = pFirst;
pFirst = newAlbum;
}
}
(note that sizeof *newAlbum is a little better than sizeof(struct list), since the former is "obviously correct" when reading the line - it will still be corret if the type of newAlbum is ever changed).
The only thing I can see wrong here is that you don't check the length of name. You should use:
strncpy(newAlbum->name, 52, name);
This will prevent overrunning the name buffer.

Resources