I'm trying to print a struct's field in C, and I have troubles with it.
I'm having 2 problems.
First, when I'm trying to print the field "courseName" of a course named "math" I get: "(null)math══════════════════════════"
Second, when I try to print the field courseNumber, it prints the courseNumber and the courseName.
can someone please tell me what I'm doing wrong?
struct Course {
char courseNumber[6];
char courseName[30];
struct Course* next;
};
struct Course* updateCoursesList(char courseDetails[], struct Course* coursesList)
{
struct Course* head = NULL;
int i = 6, j = 0;
if (coursesList == NULL) {
coursesList = (struct Course*)malloc(sizeof(struct Course));
if (coursesList == NULL)
return NULL;
head = coursesList;
strncpy(coursesList->courseNumber, courseDetails, 5);
coursesList->next = NULL;
while (courseDetails[i] != '\n') {
coursesList->courseName[j] = courseDetails[i];
i++;
j++;
}
}
else {
head = coursesList;
if (strncmp(courseDetails, coursesList->courseNumber, 5) == 0) {
while (courseDetails[i] != '\n') {
coursesList->courseName[j] = courseDetails[i];
i++;
j++;
}
return head;
}
while (coursesList->next != NULL) {
if (strncmp(courseDetails, coursesList->courseNumber, 5) == 0) {
while (courseDetails[i] != '\n') {
coursesList->courseName[j] = courseDetails[i];
i++;
j++;
}
return head;
}
else
coursesList = coursesList->next;
}
coursesList->next = (struct Course*)malloc(sizeof(struct Course));
if (coursesList->next == NULL)
return head;
strncpy(coursesList->next->courseNumber, courseDetails, 5);
coursesList->next->next = NULL;
while (courseDetails[i] != '\n') {
coursesList->next->courseName[j] = courseDetails[i];
i++;
j++;
}
}
return head;
}
int main()
{
struct Course* coursesList = NULL;
char array[30] = "12345 math\n";
coursesList = updateCoursesList(array, coursesList);
printf("%s", coursesList->courseNumber);
printf("%s", coursesList->courseName);
}
You can actually use strncpy for copying both your courseNumber and courseName because both are strings.
strncpy does not terminate the copied string with \0 terminator, so we have add the \0 at the end.
For your input char array[30] = "12345 math\n"; do as follows.
strncpy(coursesList->courseNumber, courseDetails, 5);
coursesList->courseNumber[5] = '\0';
//since your courseName is also string, you need not do piece by piece copy
strncpy(coursesList->courseName, courseDetails+6, 5);
coursesList->courseName[5] = '\0';
and below code is not required in both of your if and else parts
while (courseDetails[i] != '\n')
{
coursesList->courseName[j] = courseDetails[i];
i++;
j++;
}
NOTE: But this very weird way of reading your inputs , instead take inputs from stdin and use them, because the lengths may not be same for all courses.
Related
I tried to implement circular linked list to manage a set of tasks by a server side application. The application is multi-threaded where one thread (updater() ) reads the linked list only for read while another two (push_stream() and delete_stream()) access the linked list to add to and delete from the linked list respectively.
My problem is not all the files to be deleted (after being processed) are deleted.
struct data_stream
{
bool processed;
int count;
char filename[30];
int TYPE_GRP;
int task_type;
struct data_stream *next;
};
struct data_stream *stream_head=NULL; //global variable
main(partial code)
main()
{
_beginthread(updater, 0, NULL);
while ((new_socket = accept(srv_sock, (struct sockaddr *)&client, &c)) != INVALID_SOCKET)
{
_beginthreadex(0, 0, handle_client, &new_socket, 0, 0);
}
}
handle_client function (partial code)
handle_client()
{
//some where in handle_client
EnterCriticalSection(&stream_lock);
stream_head = push_stream(&stream_head, TYPE_GRP, task_type);
LeaveCriticalSection(&stream_lock);
}
updater function (full source code)
void updater(void *data)
{
while (1)
{
struct data_stream*temp = stream_head;
struct data_stream*first = stream_head;
struct data_stream*prev = NULL;
if (stream_head != NULL)
{
struct data_stream*next = NULL;
do
{
next = temp->next;
if (temp->processed == false&&temp->task_type == 2)
{
process_files(temp);
}
else if (temp->processed == false&&temp->task_type == 3)
{
process_others();
}
EnterCriticalSection(&stream_lock);
temp->processed = true;
LeaveCriticalSection(&stream_lock);
temp = next;
} while (temp != first);
}
if (stream_head != NULL)
{
EnterCriticalSection(&stream_lock);
stream_head=delete_stream(&stream_head);
LeaveCriticalSection(&stream_lock);
}
Sleep(6000);
}
}
process_files
void process_files(struct data_stream*temp)
{
int count = 0;
char file_to_update[50] = { NULL };
size_t name_len = strlen(temp->filename);
memcpy_s(file_to_update, name_len, temp->filename, name_len);
file_to_update[name_len] = '\0';
temp->count = 0;
FILE *list_to_update ;
fopen_s(&list_to_update , file_to_update, "r+b");
if (list_to_update != NULL)
{
char readline[100] = { '\0' };
while (fgets(readline, sizeof(readline), list_to_update ) != NULL)
{
//read a line at a time and process the list
count++;
}
temp->count = count;
fclose(list_to_update );
}
else
printf("\nerror opening file\n");
}
process_others()
void process_others(struct data_stream*temp)
{
int count = 0;
char file_to_update[50] = { NULL };
size_t name_len = strlen(temp->filename);
memcpy_s(file_to_update, name_len, temp->filename, name_len);
file_to_update[name_len] = '\0';
temp->count = 0;
FILE *list_to_update ;
fopen_s(&list_to_update , file_to_update, "r+b");
if (list_to_update != NULL)
{
char readline[100] = { '\0' };
while (fgets(readline, sizeof(readline), list_to_update ) != NULL)
{
//read a line at a time and process the list
count++;
}
temp->count = count;
fclose(list_to_update );
}
else
{
printf("\nerror opening file\n");
}
}
}
push_stream (full source code)
struct data_stream* push_stream(struct data_data_stream**head_ref, int typ_grp, int task_type)
{
struct data_stream*new_data_stream=
(struct data_data_stream*)malloc(sizeof(struct data_stream));
new_stream->processed = false;
new_stream->task_type = task_type;
new_stream->TYPE_GRP = typ_grp;
new_stream->filename[0] = NULL;
new_stream->count = 0;
new_stream->next = NULL;
if (task_type == 2)
sprintf_s(new_stream->filename, "%s%03d.txt", "file_md5_list_", stream_count);
else
sprintf_s(new_stream->filename, "%s%03d.txt", "other_list_", stream_count);
if (*head_ref == NULL)
{
*head_ref = new_stream;
new_stream->next = new_stream;
}
else
{
struct data_stream* last = (*head_ref)->next;
struct data_stream* prev = (*head_ref)->next;
while (last != *head_ref)
{
prev = last;
last = last->next;
}
new_stream->next = *head_ref;
last->next = new_stream;
}
if (stream_count > 998)
stream_count = 1;
else
stream_count++;
return new_stream;
}
delete_stream function (full source code)
struct data_stream* delete_stream(struct data_data_stream**head)
{
if (head == NULL)
return NULL;
struct data_stream*prev = NULL;
struct data_stream*temp = *head;
struct data_stream*first = *head;
do
{
struct data_stream*next = temp->next;
if (temp->processed)
{
if (prev == NULL)
*head = temp->next;
else
prev->next = temp->next;
char file_to_delete[50] = { NULL };
memcpy_s(file_to_delete, strlen(temp->filename), temp->filename, strlen(temp->filename));
DeleteFileA(file_to_delete);
free(temp);
}
else
{
prev = temp;
}
temp = next;
} while (temp != first);
if (prev == NULL)
{
return NULL;
}
return *head;
}
I am new to C and am trying to code up a data structure, primarily, a ternary search tree. I am working under the assumption (for now) that valid char inputs are being passed in. I am having some issues with my insert function. Note that I am also inserting the original string in the last TSTnode where the last character of str will also be held.
Here is what I have so far
struct TSTnode {
char* word; // NULL if no word ends here
char self;
struct TSTnode *left, *sub, *right;
};
int insert_tst(struct TSTnode** tree, const char* str) {
return _insert(tree, str, 0);
}
int _insert(struct TSTnode** tree, const char* str, int position) {
if((*tree) == NULL) {
*tree = new_tst_node(*(str+position));
position = position + 1;
if(*(str+position) == '\0') {
(*tree)->word = strcpy((*tree)->word,str);
return 1;
}
}
else if ((*tree)->self > *(str+position)) {
position = position + 1;
_insert( &((*tree)->left), str, position);
}
else if ((*tree)->self < *(str+position)) {
position = position + 1;
_insert( &((*tree)->right), str, position);
}
else {
position = position + 1;
_insert( &((*tree)->sub), str, position);
}
return 0;
}
struct TSTnode* new_tst_node(char self) {
struct TSTnode* newNode = (struct TSTnode*) malloc(sizeof(struct
TSTnode));
if (newNode == NULL) {
return NULL;
}
newNode->word = NULL;
newNode->self = self;
newNode->left = NULL;
newNode->right = NULL;
newNode->sub = NULL;
return newNode;
}
Here is how I am testing:
struct TSTnode* tree = NULL;
char* words[1] = {"hello"};
for (int i = 0; i < 1; i++) {
if (insert_tst(&tree, words[i]) == 0) {
//print some error
}
else { //success }
EDIT - My issue is that none of my conditional branches are being taken and the insert function simply goes straight to return 0.
Note: You confusingly use tree for both TSTnode* and TSTnode**. I'm going to use tree_ptr for the latter, and pretend that you did the same.
Your claim is false. The body of if((*tree_ptr) == NULL) is executed. You do have a number of problems, though.
You don't handle the case where *tree_ptr == NULL && *(str+position+1) != '\0'.
You don't correctly handle the case where *tree_ptr != NULL && *(str+position+1) == '\0'.
You always return 0 when *tree_ptr != NULL || str[1] != '\0'.
You never allocate word, but you deference it. The thing is, you shouldn't be storing the string again anyway!
You don't handle the case where str[0] == '\0' (empty string).
Fixed:
int insert_tst(struct TSTnode** tree_ptr, const char* str) {
if (!*str)
return 0; /* Zero-length strings are not supported. */
return insert_tst_helper(tree_ptr, str, 0);
}
int insert_tst_helper(struct TSTnode** tree_ptr, const char* str, int position) {
if (*tree_ptr == NULL) {
*tree_ptr = new_tst_node(*(str+position));
if (*tree_ptr == NULL)
return 0; /* Memory allocation error. */
}
if (*(str+position+1) == '\0') { /* If the next char is a NUL */
(*tree_ptr)->is_word = 1;
return 1;
}
else if ((*tree_ptr)->self > *(str+position)) {
position = position + 1;
return insert_tst_helper( &((*tree_ptr)->left), str, position);
}
else if ((*tree_ptr)->self < *(str+position)) {
position = position + 1;
return insert_tst_helper( &((*tree_ptr)->right), str, position);
}
else {
position = position + 1;
return insert_tst_helper( &((*tree_ptr)->sub), str, position);
}
}
Untested.
Let's clean this up, though.
*(str+position)simplifies tostr[position]
ch == '\0'simplifies toch == 0then to!ch
position = position + 1; return insert_tst_helper(..., str, position);simplifies to++position; return insert_tst_helper(..., str, position);then toreturn insert_tst_helper(..., str, position+1);then toreturn insert_tst_helper(..., str+1, 0);then toreturn insert_tst(..., str+1);
Why is recursion being used at all???
Fixed:
int insert_tst(struct TSTnode** tree_ptr, const char* str) {
if (!*str)
return 0; /* Zero-length strings are not supported. */
while (1) {
if (*tree_ptr == NULL) {
*tree_ptr = new_tst_node(*str);
if (*tree_ptr == NULL)
return 0; /* Memory allocation error. */
}
if (!*(str+1)) { /* If the next char is a NUL */
(*tree_ptr)->is_word = 1;
return 1;
}
int cmp = *str - (*tree_ptr)->self;
if (cmp < 0) { tree_ptr = &( (*tree_ptr)->left ); }
else if (cmp > 0) { tree_ptr = &( (*tree_ptr)->right ); }
else { tree_ptr = &( (*tree_ptr)->sub ); }
++str;
}
}
Untested.
This is my complete program:
#include <stdio.h>
#include <stdlib.h>
#define kArraySize 50
#define kFirstElement 0
struct Name {
char name[kArraySize + 1];
struct Name *nextName;
} *gFirstNameNode, *gLastNameNode;
char GetName(struct Name *currentName);
void AddToList(struct Name *currentName);
void PrintList(struct Name *gFirst);
void FreeTheMemory(struct Name *gFirst);
int main(void) {
struct Name *currentName;
char character;
int counter;
gFirstNameNode = NULL;
gLastNameNode = NULL;
do {
currentName = malloc(sizeof(struct Name));
if (currentName == NULL) {
printf("Out of Memory!\n");
exit(0);
} else {
for (counter = 0; counter <= kArraySize; counter++)
currentName->name[counter] = '\0';
}
character = GetName(currentName);
if ((currentName->name[kFirstElement]) != '\0') {
AddToList(currentName);
}
} while (character != '\r');
PrintList(gFirstNameNode);
printf("Freeing list memory");
FreeTheMemory(gFirstNameNode);
printf("\nFreeing Current Memory!\n");
free(currentName);
printf("Program Ended");
return 0;
}
char GetName(struct Name *currentName) {
char c;
int counter = 0;
printf("Enter a name (hit 'return' to exit):");
for (counter = 0; (counter <= kArraySize) && ((c = getchar()) != '\n'); counter++) {
currentName->name[counter] = c;
}
if (counter == 0) {
return '\r';
} else {
currentName->name[counter + 1] = '\0';
return '\0';
}
}
void AddToList(struct Name *currentName) {
if (gFirstNameNode == NULL) {
gFirstNameNode = currentName;
} else {
gLastNameNode->nextName = currentName;
}
gLastNameNode = currentName;
currentName->nextName = NULL;
}
void PrintList(struct Name *gFirst) {
struct Name *currentPointer;
if (gFirstNameNode == NULL) {
printf("No names in list\n");
printf("----------------\n");
} else {
for (currentPointer = gFirst; currentPointer != NULL; currentPointer = currentPointer->nextName) {
printf("Name: %s\n", currentPointer->name);
}
}
}
void FreeTheMemory(struct Name *gFirst) {
struct Name *currentPointer;
for (currentPointer = gFirst; currentPointer != NULL; currentPointer = currentPointer->nextName) {
free(currentPointer);
printf(".");
}
}
This is where I'm uncertain as to whether what I'm doing is correct. I'm teaching myself C all by myself so please bear with me. What I want to do is delete the node of the linked list from the first node till the last node. For that I created the following function. :
void FreeTheMemory(struct Name *gFirst) {
struct Name *currentPointer;
for (currentPointer = gFirst; currentPointer != NULL; currentPointer = currentPointer->nextName) {
free(currentPointer);
printf(".");
}
}
I'm not sure if by freeing the currentPointer whether I'm actually freeing the linked list. In other words I'm wondering if my logic is correct. I've got no one to ask so I would greatly appreciate some help.
You have a problem doing this:
free(currentPointer);
followed by this:
currentPointer = currentPointer->nextName
You can't deference currentPointer to get the next name after you've freed it.
Instead you should do something like:
currentPointer = gFirst;
while ( currentPointer ) {
struct Name * next = currentPointer->nextName;
free(currentPointer);
currentPointer = next;
}
#include <stdio.h>
#include <stdlib.h>
struct treeNode
{
char *word;
int NumberCnt;
struct treeNode *rightPTR, *leftPTR;
};
typedef struct treeNode node;
node *rootPTR = NULL;
void freeTree(node *currPTR)
{
if (currPTR!= NULL)
{
freeTree(currPTR -> leftPTR);
free(currPTR);
freeTree(currPTR -> rightPTR);
}
}
void printTree(node *currPTR)
{
if (currPTR != NULL)
{
printTree(currPTR ->leftPTR);
printf("%s appeared:%d times\n", currPTR->word, currPTR->NumberCnt);
printTree(currPTR ->rightPTR);
}
}
int insertNode (char* input)
{
node *tempPTR = malloc(sizeof(node));
tempPTR -> word = input;
tempPTR -> NumberCnt=0;
tempPTR -> leftPTR = NULL;
tempPTR -> rightPTR = NULL;
if (rootPTR == NULL)
{
rootPTR = tempPTR;
rootPTR -> NumberCnt++;
}
else
{
node *currPTR = rootPTR;
node *prevPTR = NULL;
while (currPTR != NULL)
{
int comp = strcmp(input, (currPTR->word));
if (comp == 0)
{
printf ("Entry already exists\n");
currPTR->NumberCnt++;
return 1;
}
else if (comp < 0)
{
prevPTR = currPTR;
currPTR = currPTR->leftPTR;
}
else if (comp > 0)
{
prevPTR = currPTR;
currPTR = currPTR->rightPTR;
}
}
int comp = strcmp(input, (prevPTR ->word));
if (comp < 0)
{
prevPTR->leftPTR = tempPTR;
prevPTR ->NumberCnt++;
}
else if (comp > 0)
{
prevPTR->rightPTR = tempPTR;
prevPTR->NumberCnt++;
}
return 0;
}
printf("root1%s\n",rootPTR->word);
return 2;
}
int search(char* input)
{
if (input == rootPTR ->word)
{
printf("Node found %s\n", rootPTR->word);
return 0;
}
else
{
if (input < rootPTR ->word)
{
node *currPTR = rootPTR->leftPTR;
while (currPTR != NULL)
{
if (input == currPTR->word)
{
printf("Node found %s\n", currPTR->word);
return 0;
}
else if (input < currPTR->word)
{
currPTR = (currPTR -> leftPTR);
}
else if (input > currPTR->word)
{
currPTR = (currPTR -> rightPTR);
}
}
printf ("Node not in tree\n");
return 1;
}
if (input > rootPTR ->word)
{
node *currPTR = rootPTR->rightPTR;
while (currPTR != NULL)
{
if (input == currPTR->word)
{
printf ("Node found %s\n", currPTR->word);
return 0;
}
else if (input < currPTR->word)
{
currPTR = (currPTR -> leftPTR);
}
else if (input > currPTR->word)
{
currPTR = (currPTR ->rightPTR);
}
}
printf ("Node not in tree\n");
return 1;
}
}
return 2;
}
void fixWord(char* buff)
{
char* unfixed = buff;
char* fixed = buff;
while (*unfixed)
{
if (isalpha(*unfixed))
{
*fixed=tolower(*unfixed);
*fixed++;
}
*unfixed++;
}
*fixed=0;
}
int main()
{
FILE *ptr_file;
char buff [100];
//ptr_file = fopen ("sherlock.txt", "r");
ptr_file = fopen ("input.txt", "r");
if (!ptr_file)
printf("File read error");
while(fscanf(ptr_file, "%s ", buff ) != EOF)
{
int comparison = strcmp(buff, "endoffile");
if (comparison == 0)
{
return 0;
}
fixWord(buff);
insertNode(buff);
}
fclose(ptr_file);
printf("root:%s\n", rootPTR->word);
return 0;
}
Ok I have this binary tree which is taking string inputs from a file. It works if I pass strings directly to the tree, however when I attempt to pass it the strings I read in form the file it keeps on replacing the root node and does not add them correctly to the tree.
buff is current line value and overwritten on each line reading:
insertNode(buff);
insertNode assigns overwriten buffer.
int insertNode (char* input)
{
node *tempPTR = malloc(sizeof(node));
tempPTR -> word = input;
....
So, you should dynamic allocation for input value as:
int insertNode (char* input)
{
node *tempPTR = malloc(sizeof(node));
tempPTR -> word = strdup(input);
....
You're passing buff to your insert function, and it's storing that in the node. So all your nodes will end up pointing to the same address, that of buff in main.
You need to allocate storage for each string in each node, and copy your input into that. And remember to deallocate properly when you delete your tree.
strdup can be handy for that if your library has it.
I'm making a program that generates a text file that contains the occurrences of words and the line number of each occurrence of another text file. I'm using an AVL tree struct that contains the word and a linked list struct that contains one node for each line number. Here are the struct definitions:
struct llnode {
struct llnode *next;
int num;
};
struct node {
char *word;
struct llnode *head;
struct node *left;
struct node *right;
int height;
};
I get a segmentation fault when I try to print to the text file using the below functions.
void listprint(struct llnode *p) {
if(p->next == NULL) {
printf("%d", p->num);
} else {
printf("%d, ", p->num);
listprint(p->next);
}
}
void treeprint(struct node *p) {
if(p != NULL) {
treeprint(p->left);
printf("%s: ", p->word);
listprint(p->head);
treeprint(p->right);
}
}
Specifically the problem is this line
if(p->next == null) {
gdb gives me
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x0000000000000000
Thanks for your help.
Edit:
void listinsert(struct llnode *p) {
struct llnode *prev = p;
while(p != NULL) {
prev = p;
p = p->next;
}
p = lalloc();
p->num = line;
p->next = NULL;
prev->next = p;
struct node *addtree(struct node *p, char *w) {
int cond;
if(p == NULL) {
p = talloc();
p->head = NULL;
p->word = mystrdup(w);
p->head = listinsert(p->head);
p->left = p->right = NULL;
} else if((cond = strcmp(w, p->word)) == 0) {
listinsert(p->head);
} else if(cond < 0) {
p->left = addtree(p->left, w);
if(height(p->left)-height(p->right) == 2) {
if(strcmp(w, p->left->word) < 0) {
p = singleleft(p);
} else {
p = doubleleft(p);
}
}
} else {
p->right = addtree(p->right, w);
if(height(p->right)-height(p->left) == 2) {
if(strcmp(w, p->right->word) > 0) {
p = singleright(p);
} else {
p = singleleft(p);
}
}
}
return p;
int getword(char *word, int lim) {
int c;
char *w = word;
while(isspace(c = getch()));
if(c == '\n') {
line++;
}
if(c != EOF) {
*w++ = c;
}
if(!isalpha(c)) {
*w = '\0';
return c;
}
for( ; --lim > 0; w++) {
if(!isalnum(*w = getch())) {
ungetch(*w);
break;
}
}
*w = '\0';
return word[0];
In listprint, you are not checking if p is null before checking if p->next is null.
Try this.
llnode* listinsert(struct llnode *p) {
struct llnode *prev = p;
if( NULL == prev ) {
prev = lalloc();
prev->num= line;
prev->next = NULL;
return prev;
}
while(prev->next != NULL) {
prev = prev->next;
}
prev->next = lalloc();
prev = prev->next;
prev->num = line;
prev->next = NULL;
return p;
}