When should you free memory dynamically allocated? - c

Essentially, I have created a piece of Code which consists of a tree, whereby each tree node has its own linked list containing data, (each treeNode containing data as well). So that each treeNode can have multiple data items for that specific treeNode.
For this structure therefore to be created, I calloc a treenode, pass the address of that treenode to a createListNode function, and calloc a ListNode. My confusion stems really from, where exactly should I be freeing memory? Merely at the end of the program before return 0; in main, or elsewhere. Baring in mind once all the input is added to the tree and list, it then asks the user for a name, and displays the linked list of data appropriate for that name.
Cheers.
T.C.
EDIT:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
typedef struct ListNode {
char *number;
struct ListNode *next;
}ListNode;
typedef struct TreeNode {
char *name;
ListNode *numbers;
struct TreeNode *left;
struct TreeNode *right;
}TreeNode;
TreeNode* AddNode(TreeNode *, char *, char *);
void AddNum(TreeNode *, char *);
void N_Print(TreeNode* root);
TreeNode* SearchTree(TreeNode* root, char *search);
int main(void) {
char my_string[50], name[25], number[25];
TreeNode *root = NULL;
while ((fgets(my_string, 50, stdin)) != NULL) {
if (my_string[0] == '.')
break;
sscanf(my_string, "%s %s", name, number);
root = AddNode(root, name, number);
}
N_Print(root);
free(root);
free(root->numbers);
return 0;
}
TreeNode* AddNode(TreeNode *root, char *name, char *number) {
int comparison;
if (root == NULL) {
root = (TreeNode*)calloc(1,sizeof(TreeNode));
root->name = strdup(name);
root->left = root->right = NULL;
AddNum(root, number);
}else if ((comparison = strcasecmp(name, root->name)) < 0)
root->left = AddNode(root->left, name, number);
else if ((comparison = strcasecmp(name, root->name)) > 0) {
root->right = AddNode(root->right, name, number);
} else if ((comparison = strcasecmp(name, root->name)) == 0 ) {
AddNum(root, number);
}
return root;
}
void AddNum(TreeNode *tn, char *number) {
ListNode *ln = (ListNode *)calloc(1, sizeof(ListNode));
ln->number = strdup(number);
ln->next = tn->numbers;
tn->numbers = ln;
}
TreeNode* SearchTree(TreeNode* root, char *search) {
int comparison;
if (root == NULL) {
return NULL;
} else if ((comparison = strcasecmp(search, root->name)) == 0) {
return root;
} else if ((comparison = strcasecmp(search, root->name)) < 0) {
return SearchTree(root->left, search);
} else if ((comparison = strcasecmp(search, root->name)) > 0)
return SearchTree(root->right, search);
}
void N_Print(TreeNode* root) {
TreeNode* search_val;
char search[25];
while(1) {
printf("Type a name please: ");
scanf("%24s", search);
if (search[0] == '.')
break;
search_val = SearchTree(root, search);
if (search_val == NULL) {
printf("NOT FOUND\n");
continue;
}
ListNode* ln = search_val->numbers;
while ( ln != NULL) {
printf("%s\n", ln->number);
ln = ln->next;
}
}
}

You should free the memory when it is no longer needed. That of course depends on your application's needs.
In garbage collected environments (e.g. Java) the garbage collector frees memory when nothing is pointing at it. Following that as a starting point, you want to be sure to free memory before you remove your references to it.

The best plan (IMO) is to free memory at the point where you don't need to access it any more. however if you only use a small amount of dynamically allocated memory it probably wont make much of a difference if you do it all at the end of your program (assuming you keep track of it all)

It's simple:
You free the memory when you have no more need for it. In your case, it seems you'll never have to remove a node so don't worry about deleting any. It is automatically freed when your program exits. Be careful though, you should delete all memory which all of its pointers that reference it get out of scope, making it unusable. This may cause memory leaks.

When you no longer need the resources acquired from free store. So, it depends on what point you are not using calloc resources, you can start free it. But beware of dangling references.

You free the memory, once you have no use for it anymore. If that happens before program exit, well you free it before return. If the program wants to continue on whatever and you don't have need for the tree anymore, you free it and the continue with the program.
If for example the linked lists in the tree could at some stage shrink, the no-more-used nodes should be immediately freed.

You can free all the data as soon as you don't need it anymore, like when you're done printing it. In your case, if this is all what you program do it does not really matter as your kernel will free all memory allocated by your program at termination. However it matters if the program keeps running as it means you eating memory that cannot be used for other programs.
It's a bit like with previous version of firefox where it did not release memory after closing a tab. The program kept asking for more and more memory without releasing it.

As everyone above says, free it whe you don't need it anymore, but additionally it is often a good idea to try to free on the same level that you create. This is more complicated when you are passing references around and such.

Related

I'm making a linked list of strings in C, and having a problems

I am beginner in programming. thanks for helping me.
I am trying to make a linked list in strings.
inputs are strings, and it ends if input is "exit".
But when i compile it, it prints out the last inputs only, and i can't solve it!
From function addrear, it distinguishes whether data is stored in linked list for the first time of not. and store data and links to another Node appropriately.
From function printlist, it starts from the start of linked list and prints out the data in each nodes.
I've tried it with integer type , and when this code was executed with int , not string, it worked correctly, so i think error came out from character array.
ex) input1 "dump",
input2 "end",
input3 "dir",
input4 "exit",
than output would be
dump,
end,
dir,
exit
but it comes out
exit
exit
exit
exit
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char instruction[1000];
struct Node {
struct Node* next;
char* data;
};
struct Node* pStart = NULL;
struct Node* pEnd = NULL;
void addrear(char* val)
{
struct Node* Current;
Current = (struct Node*)malloc(sizeof(struct Node));
Current->data = val;
Current->next = NULL;
//printf("%s\n", Current->data);
if (pStart == NULL)
{
pStart = Current;
pEnd = Current;
}
else
{
pEnd->next = Current;
pEnd = Current;
}
}
void printlist(struct Node* Current)
{
Current = pStart;
while (Current != NULL)
{
printf("%s\n", Current->data);
Current = Current->next;
}
}
int main()
{
int i;
while (1)
{
printf("sicsim> ");
fgets(instruction, sizeof(instruction), stdin);
instruction[strlen(instruction) - 1] = '\0';
addrear(instruction);
if (strcmp(instruction, "exit") == 0)
{
break;
}
}
printlist(pStart);
}
As MZB answered, your problem is you are confusing reference and value.
You said:
"I've tried it with integer type , and when this code was executed with int , not string, it worked correctly, so i think error came out from character array."
There's a huge difference between assigning the value of int and assigning a string. you are going to get the value of this int anyway- you don't care where he "lives". It is also true when we talk about char, but if you talk about strings - you want to point to this string - so you want to point at some place which can hold your data and would not be modified.
If you want to save this string you need to know that the string storage place would not be accessed.
Therefore you should copy char by char so you wouldn't care if "instruction" will be assign as something else.
Your mistake is that you are storing a pointer to the instruction buffer in the Node structure. Each time you read a string, you overwrite that buffer with the string you read in.
You need to allocate memory for each string.
If you're learning C++, check out the documentation on "new" (how you should allocate the space for Node etc.) malloc is a lower-level C method of doing things.

Linked list in a shared memory segment

I am currently working on a part where a linked list, one linked list node has multiple variable data, is to be saved in a shared memory segment so that another program can read that list and do operations accordingly.
I have previously worked on socket programming, but sending a stream of data does not fulfill my purpose, as I have to do validation based on reading one node/element at a time. So, of all the IPC's, I think shared memory would be the best as it also has good performance than others(in this case, not generally).
The following is the struct that I have made:
struct DNode {
char *polname;
char *devname;
char *status;
char *srczone;
char *dstzone;
char *srcaddr;
char *dstaddr;
char *srcuser;
char *app;
char *service;
char *urlcategory;
char *action;
char *vulnerability;
char *value;
struct DNode *next;
};
struct DNode *head = NULL;
struct DList {
DNode pool[MAX_DNODE]; // fixed-size space for nodes
size_t npool; // used space in pool
size_t pfree; // pointer to re-use freed nodes
size_t head; // global list head
};
DList *dlist;
DNode *dnode_alloc(void)
{
if (dlist->pfree != DNULL) {
DNode *node = dlist->pool + dlist->pfree;
dlist->pfree = dlist->pool[dlist->pfree].next;
return node;
} else {
if (dlist->npool < MAX_DNODE) return &dlist->pool[dlist->npool++];
}
return NULL;
}
void dnode_free(DNode *node)
{
if (node) {
node->next = dlist->pfree;
dlist->pfree = node - dlist->pool;
}
}
DNode *dnode(size_t index)
{
return (index == DNULL) ? NULL : dlist->pool + index;
}
DNode *dnode_next(const DNode *node)
{
return dnode(node->next);
}
DNode *dnode_push(size_t *head, const char *str)
{
DNode *node = dnode_alloc();
if (node) {
strncpy(node->polname, str, sizeof(node->polname));
node->next = *head;
*head = node - dlist->pool;
}
return node;
}
void dnode_pop(size_t *head)
{
if (*head != DNULL) {
size_t next = dlist->pool[*head].next;
dnode_free(&dlist->pool[*head]);
*head = next;
}
}
int list_insert_front(struct node* new_node) {
struct node *temp;
temp = malloc(sizeof *temp);
if (temp && new_node) {
memcpy(temp, new_node, sizeof(struct node));
temp->next = head;
head = temp;
return 1;
}
return 0;
}
int main(int argc, char **argv)
{
struct Dnode *iter = head;
int shmid;
xmlDocPtr doc;
xmlNode *root_element = NULL;
if (argc != 2)
{
printf("\nInvalid argument\n");
return(1);
}
doc = xmlReadFile(argv[1], NULL, XML_PARSE_NOBLANKS | XML_PARSE_NOERROR | XML_PARSE_NOWARNING | XML_PARSE_NONET);
if (doc == NULL)
{
fprintf(stderr, "Document not parsed successfully.\n");
return 0;
}
root_element = xmlDocGetRootElement(doc);
if (root_element == NULL)
{
fprintf(stderr, "empty document\n");
xmlFreeDoc(doc);
return 0;
}
printf("Root Node is %s\n", root_element->name);
traverse_dom_trees(root_element);
shmid = shmget(IPC_PRIVATE, sizeof(DList), IPC_CREAT | 0660);
if (shmid < 0) exit (1);
dlist = shmat(shmid, NULL, 0);
if (dlist == (void *) (-1)) exit(1);
dlist->head = DNULL;
dlist->pfree = DNULL;
dlist->npool = 0;
while(iter != NULL){
dnode_push(&dlist->head, head->polname);
dnode_pop(&dlist->head);
iter = head->next;
}
shmdt(dlist);
xmlFreeDoc(doc); // free document
xmlCleanupParser(); // Free globals
return 0;
}
As you can see, I have also included an XML parser part in the main function so as to give you an idea of what I am taking as an input. But the part where I am stuck is how to save/use this struct inside a shared memory, and making it easy for the other program to access it.
Please can somebody provide me with some pseudo-code for the same as I have never used such C functionalities before and am absolutely clueless on how to approach this.
Any and all suggestions are welcome and am thankful in advance.
Edit 1
Using Centos7 on a virtual machine since somebody pointed out that mentioning the platform would be fruitful.
Edit 2
Just added some code to implement shared memory segments, and it does not give me any such errors. What my concern is:
Is it doing what I intended?
Is the approach correct?
I know I am currently just pushing one element but this sure is right, right?
Am I wasting time and efforts trying to work it out using shared memory?
In general you cannot warrant that a shared memory segment will occupy the same virtual address range in one process than in other. So you'll have a problem when trying to interpret the values in the pointer fields, as they represent the address of the pointed object in the virtual address space of the process that wrote there the pointer value and this can be different if both processes map the shared memory segment at different places.
You can pass the mmap call a pointer to tell the system where in your virtual address space you want the segment to be mapped, so the shared pointers point to the same place in both virtual address spaces. But that pointer is only a hint, and the operating system is not forced to follow your pointer.
There are two solutions for this. The first is to offset the pointer values, so you construct your virtual address space pointer from the one you see in the shared segment. The second is to ensure your memory segments both are mapped to the same address. This has to be coordinated between both processes (but it has to be done only once, at memory mapping) as the place that is good for one can be forbidden for the other (because it has mapped some other thing there)
In 64bit architectures this is easy, as you have a zillion virtual addresses to map the segment to, and probably you can select an address without clashing with other subsystem. Think that in 32bit systems, normally shared libraries consume a bunch of addresses for the data segments of the modules herein, and the stacks makes provision for large amounts of memory, and the heap also... so you have to plan the thing before an attempt of putting both segments in a shared, identical address.
NOTE
In your particular case, that almost all the fields of the structure are pointers, this applies to all the fields, and not only the list linking ones. Not only all the list nodes must lie in the shared segment... also all the strings, and everything you access that is shared.
You will need to:
Setup shared memory on your platform - see here.
In your program, call shm_open to open the shared memory and use mmap to access it using a pointer - see here.
Accessing shared memory from different processes/thread must use some arbitration/mutual exclusion mechanism - see here.

Adding a struct to linkedlist in c

I'm trying to add Process-structs to a linked list. Their definitions are as follows.
typedef struct {
char name[2];
int duration;
int priority;
int arrival;
} Process;
typedef struct {
Process p;
struct LinklistNode* next;
} LinklistNode;
The function that I'm using to create the process looks like this.
Process makeProcess(char nameIn[2], int durationIn, int priorityIn, int arrivalIn){
Process p = (Process*) malloc(sizeof(Process)); //getting an error
p->name = nameIn;
p->duration = durationIn;
p->arrival = arrivalIn;
p->priority = priorityIn;
}
I'm not sure that I'm doing that part right, and I'm also not sure that I should be returning a process or have it void, as this process "should" go into the linked list.
My code for creating a linked list node is as follows:
LinklistNode* create_linklist_node(Process pIn) {
LinklistNode* node = (LinklistNode*) malloc(sizeof(LinklistNode));
node->p = pIn;
node->next = NULL;
return node;
}
For a bit more context I'll be calling these functions in main() where I've tokenized a string from a file I'm reading from. I'm wondering the best way to make the Process struct. Right now I have this:
while(!feof(fPointer)){
//the i counter is for the first line in the text file which I want to skip
while ((fgets(singleLine, 1500, fPointer) != NULL) && !(i == 0)){
char *token = strtok (singleLine, delimit);
while(token != NULL){
printf(" %s\n", token);
token = strtok(NULL, delimit);
}
}
i++;
}
Bit of a long question but any references or additional information is always appreciated. Let me know if you have additional questions or need more info on what I'm doing or why I'm doing something. Or if you can find an example of something similar, that would be greatly appreciated as I haven't had much luck with that so far.
Thanks
You seem to have some issues with pointers. In this line
Process p = (Process*)malloc(sizeof(Process)); //getting an error
what you should be doing is
Process *p = malloc(sizeof(Process));
because unlike a new in some other languages, the malloc will just return a void *, (which in pure C can be automatically converted to any other data object pointer type). That pointer stores the address of the memory allocated for your struct. Of course you will also have to return the pointer, thus changing the return type to Process*.
Continuing with your original design, you would also have to store the Process* in the list-node, and consequently pass it to your construction method (LinklistNode* create_linklist_node(Process *pIn)).
You would then have to free both the node and possibly the pointer to the contained struct, if it is no longer used anywhere else, when you destroy the node.
However, given the size of your Process struct, I would suggest something else:
Since you already have your list nodes like this:
typedef struct{
Process p;
struct LinklistNode* next;
}LinklistNode;
You would allocate the memory for the actual process struct inside the node in during the call to create_linklist_node. Then you can just pass in a Process struct that is on the stack and copy it into the struct in the list, which lives in the heap-memory allocated by the create-call. In that case you don't need to dynamically allocate the Process at all, and the pointer issues in the first part become irrelevant.
LinkListNode *create_linklist_node(Process proc)
{
LinklistNode *p = malloc(sizeof *p);
if (p == NULL)
{
perror("Failed to allocate new node: ");
exit(EXIT_FAILURE);
}
p->p = proc;
p->next = NULL;
return p;
}
You would then do something like this:
Process proc = {{'a', 'b'}, 0, 0, 0};
LinklistNode *p = create_linklist_node(proc);
However, it is more common to have a method that directly creates and inserts the node into the list, for example, given:
typedef struct {
LinklistNode *head;
} Linklist; //doing this is kinda optional, using a simple pointer would do too
you could insert at the head of the list by doing something like:
void insert (Linklist *list, Process ins)
{
LinklistNode *tmp = create_linklist_node(ins);
tmp->next = list->head;
list->head = tmp;
}

inserting node (Binary search tree) C

I'm trying to insert a node in a binary search tree and I'm getting a little problem.
#include "stdafx.h"
#include <string.h>
#include <stdlib.h>
typedef struct Node{
char name[100];
struct Node *pGauche;
struct Node *pDroit;
}Node;
void getName(char[]);
void copy(Node **, Node *,char[]);
void menu(Node **);
void add(Node **);
void search(char[],Node**, Node **,Node **);
void print(Node **);
void inOrder(Node *);
void main(void)
{
Node *root = NULL;
menu(&root);
system("pause");
}
void menu(Node **root)
{
for (int i=0;i<10;i++)
{
add(root);
}
print(root);
}
void add(Node **root)
{
char name[100];
getName(name);
Node *p = NULL;
Node *savep = NULL;
search(name,root,&p,&savep);
copy(root,savep,name);
}
void search(char name[],Node **root, Node **p, Node **savep)
{
*p = *root;
while ((p == NULL) && (strcmp((*p)->name,name) != 0))
{
*savep = *p;
if (strcmp(name,(*p)->name) < 0)
*p = (*p)->pGauche;
else
*p = (*p)->pDroit;
}
}
void getName(char name[])
{
printf("What name do you want to add\n");
scanf("%s",name);
fflush(stdin);
}
void copy(Node **root, Node *savep, char name[])
{
Node *newp = (Node *) malloc(sizeof(Node*));
newp->pDroit = NULL;
newp->pGauche = NULL;
strcpy(newp->name,name);
printf("%s",newp->name);
if (*root == NULL)
*root = newp;
else
{
if (strcmp(name,savep->name) < 0)
savep->pGauche = newp;
else
savep->pDroit = newp;
}
free(newp);
}
void print(Node ** root)
{
Node *p = *root;
inOrder(p);
}
void inOrder(Node *p)
{
if (p != NULL)
{
inOrder(p->pGauche);
printf("%s\n",p->name);
inOrder(p->pDroit);
}
}
I know there are some really odd function and useless functions, but this just a "test" for a slightly bigger school project so it will get useful in time, right now I would just like to get the binary tree working !
So basically the problem is that I'm getting a "Access violation reading location" after I type in the second name... I'm guessing when doing the strcmp, but I'm really not sure :/
I'd really be glad if someone could help me getting this running :)
A couple of things to get you started. I haven't looked into it too deeply, so you will probably have to continue to drill down into more issues, but fix these things just to get you started:
In this code in search():
while ((p == NULL) && (strcmp((*p)->name,name) != 0))
The p parameter will never be NULL. So, the while loop is never entered. This means that savep would not get set to any value, and is NULL when you call copy() in your add() function. The copy() function then dereferences the invalid pointer reference, which caused the problem you observed.
You actually want to test to see if *p is NOT NULL. This allows you to legally dereference it.
while ((*p != NULL) && (strcmp((*p)->name,name) != 0))
Secondly, as hmjd identified, you do not allocate enough memory for your node inside copy().
Node *newp = (Node *) malloc(sizeof(Node*));
You are only allocating enough memory for one pointer, not for an entire node. Also, you should not cast the return value of malloc() when coding in C (it will hide a bug that can lead to a crash in the worst case).
Node *newp = malloc(sizeof(Node));
Thirdly, you need to retain the memory you allocate for your nodes rather than freeing them immediately after inserting it at the end of copy():
// I need this memory for my tree!
//free(newp);
If you call free() like you did, then your tree will be pointing into freed memory, and to access them would cause undefined behavior.
One minor thing: You shouldn't do fflush(stdin), as fflush() is only for output streams.
This is incorrect:
while ((p == NULL) && (strcmp((*p)->name,name) != 0))
and will result in a NULL pointer being dereferenced, which is undefined behaviour. Change to:
while (*p && strcmp((*p)->name,name) != 0)
This is incorrect:
Node *newp = (Node *) malloc(sizeof(Node*));
as it is only allocating enough for a Node*, when it needs to be allocating a Node. Change to:
Node *newp = malloc(sizeof(*newp));
and don't free() it in the same function as it is required later. free()ing the Node means the list has dangling pointers and dereferencing one is undefined behaviour, and a probable cause of the access violation.
Note:
fflush(stdin);
is undefined behaviour. From the fflush() reference page:
Causes the output file stream to be synchronized with the actual contents of the file. If the given stream is of the input type, then the behavior of the function is undefined.

C Segmentation fault even when using EOF [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
I'm loading a file into memory and I am doing so with the following statement:
if ((ch = fread(&temp[i],1,1,loadDict)) == EOF)
break;
But I receive a segmentation fault. Upon inspection using gdb I verified that the fault is happening at this line (the if statement, before the break). Why does it not see that it will fault (the whole point of using EOF)?
I thought it might be that I'm using the EOF in an if statement rather than within a while() statement. Is it possible to use EOF in an if statement?
Update: More Code
bool load(const char* dictionary)
{
FILE* loadDict = fopen(dictionary, "r");
char* new = malloc(sizeof(char)); // for storing the "new-line" character
*new = 0x0A;
// defines a node, which containes one word and points to the next word
typedef struct node
{
char* word;
struct node* next;
}
node;
node* head = malloc(sizeof(node));
node* temp = malloc(sizeof(node));
head->next=temp;
// copies a word from the dictionary file into a node
int* numStore = malloc(sizeof(int)); //count for number of words in dictionary
int num = 0;
int ch = 0; // to hold for EOF
int flag = 0; // for breaking out of while loop
while(true)
{
node* newNode = malloc(sizeof(node));
temp->next=newNode;
temp->word=malloc(46);
int i = -1;
do
{
i++;
if (!feof(loadDict) || !ferror(loadDict))
{
flag = 1;
break;
}
fread(&temp[i],1,1,loadDict);
if (memcmp (new, &temp[i], 1) == 0)
num += 1;
}
while(memcmp (new, &temp[i], 1) != 0);
temp=newNode;
if (flag == 1)
break;
}
numStore = &num;
return true;
}
typedef struct node
{
char* word;
struct node* next;
}
The structure that you defined can crash, at least the implementations I have seen has. The char* inside the node has no fixed value. So when you do :
node* head = malloc(sizeof(node));
The malloc() will allocate a memory of (taking 1 byte for char pointer, and an int size pointer for node, defaulting to 4 bytes on a 32-bit machine) 5 bytes. What happens when you read more than 5 bytes?
Also, you are needlessly complicating this:
int* numStore = malloc(sizeof(int));
If you want to store the number of words in the dictonary, straight away use an int numstore, less headache :)
while(true)
{
node* newNode = malloc(sizeof(node));
temp->next=newNode;
temp->word=malloc(46);
...
}
Now, this here is an interesting concept. If you want to read till the end of file, you have got two options:
1) use feof()
2) at the end of the loop, try this:
while(true)
{
....
if(fgetc(loadDict)==EOF) break; else fseek(loadDict,-1,SEEK_CUR);
}
Also, this line: temp->word=malloc(46);
Why are you manually allocating 46 bytes?
Armin is correct, &temp[i], while i does get allocated to 0, the do{...}while(); is completely unnecessary.
Also from man fread : http://www.manpagez.com/man/3/fread/
You are reading what looks to me like 1 character.
In my opinion, try something like this:
set a max value for a word length (like 50, way more for practical purposes)
read into it with fscanf
get its length with fscanf
allocate the memory
Also, you do not need to allocate memory to *head; It can be kept as an iterator symbol
I almost forgot, how are you going to use the returned list, if you are returning bool, and the *head is lost, thus creating a memory leak, since you can't deallocate the rest? And unless you are using c99, c doesn't support bool
/*Global declaration*/
typedef struct node
{
char* word;
struct node* next;
}node;
node *head, *tmp;
/* for the bool if you really want it*/
typedef enum { false, true } bool;
node* load(const char* dictionary)
{
FILE* loadDict = fopen(dictionary, "r");
char word[50];
int num = 0;
int len;
node *old;
while(true)
{
/*node* newNode = malloc(sizeof(node));
temp->next=newNode;
temp->word=malloc(46);*/
fscanf(loadDict,"%s ",word);
len = strlen(word);
tmp = malloc(len + sizeof(node));
strcpy(tmp->word,word);
tmp->next = NULL;
if(head==NULL)
{
head = tmp;
old = head;
}
else
old->next = tmp;
old = tmp;
num++;
if(fgetc(loadDict)==EOF) break; else fseek(loadDict,-1,SEEK_CUR);
}
printf("number of counted words::\t%d\n",num);
fclose(loadDict);
return head;
}
Also, please remember that i have only accounted for the act that words are separated by one space per, so please load the file t=like that, or change the algo :) Also, be sure to free the memory after using the program !
void freeDict()
{
node *i;
while(head!=NULL)
{
i = head;
head = head->next;
free(i);
}
}
Hope this helps :)
This compiles...I've now run it too. The error handling on failure to allocate is reprehensible; it should at minimum give an error message and should probably free all the allocated nodes and return 0 (NULL) from the function (and close the file).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Node
{
char *word;
struct Node *next;
} Node;
Node *dict_load(const char *dictionary)
{
FILE *loadDict = fopen(dictionary, "r");
if (loadDict == 0)
return 0;
Node *head = 0;
char line[4096];
while (fgets(line, sizeof(line), loadDict) != 0)
{
size_t len = strlen(line); // Includes the newline
Node *node = malloc(sizeof(*node));
if (node == 0)
exit(1); // Reprehensible
node->word = malloc(len);
if (node->word == 0)
exit(1); // Reprehensible
memmove(node->word, line, len - 1); // Don't copy the newline
node->word[len-1] = '\0'; // Null terminate the string - tweaked!
node->next = head;
head = node;
}
fclose(loadDict);
return head;
}
If you've got to return a bool from the function, then you probably need:
static bool dict_load(const char *dictionary, Node **head)
If the argument list is fixed at just the file name, then you're forced to use a global variable, which is nasty on the part of the people setting the exercise. It's 'doable' but 'ugly as sin'.
The code above does work (note the tweaked line); adding functions dict_free() and dict_print() to release a dictionary and print a dictionary plus proper error handling in dict_load() and a simple main() allows me to test it on its own source code, and it works (printing the source backwards). It gets a clean bill of health from valgrind too.
You're use of temp[i] raises suspicion that you might be accessing outside memory.
To quote from K&R:
If pa points to a particular element of an array, then by definition pa+1 points
to the next element, pa+i points i elements after pa, and pa-i points i elements
before.
These remarks are true regardless of the type or size of the variables in
the array a. The meaning of ``adding 1 to a pointer,'' and by extension,
all pointer arithmetic, is that pa+1 points to the next object, and pa+i
points to the i-th object beyond pa.

Resources