I'm writing a stack that's a linked list of data (void type). The data I am testing, is
struct my_data {
int val;
char name[60];
};
struct my_stack_node {
void *data;
struct my_stack_node *next;
};
struct my_stack {
int size;
struct my_stack_node *first;
};
the data used to be pushed, is initialized like this:
s1 = my_stack_init(sizeof(struct my_data));
if (!s1) {
puts("Error in my_stack_init()");
exit(1);
}
printf("\ns1 initialized, size of data: %lu\n", sizeof(struct my_data));
for (int i = 0; i < NODES; i++) {
data = malloc(sizeof(struct my_data)); // We must allocate static memory
data->val = i;
sprintf(data->name, "Value %d", i);
if (my_stack_push(s1, data)) {
puts("Error in my_stack_push()");
exit(1);
}
} //s1 is the stack we are using here
And pushing them by my_stack_push(s2, data); stack and the data as the arguments.
My push function is this one:
int my_stack_push(struct my_stack *stack, void *data){
if(stack == NULL && sizeof(data)> 0){
printf("Null Stack or data size error.\n");
//la pila debe existir
return -1;
}
else {
struct my_stack_node *nodeToPush = malloc(sizeof(struct my_stack_node));
nodeToPush -> data = data;
if(stack -> first == NULL) {
nodeToPush -> next = NULL;
stack -> first = nodeToPush;
}
else {
nodeToPush -> next = stack -> first;
stack -> first = nodeToPush;
}
}
return 0;
}
And my pop function is this one
void *my_stack_pop(struct my_stack *stack){
struct my_stack_node *node = stack->first;
if(stack->first == NULL){
return 0;
}
stack->first = node->next;
void *ret = node->data;
free(node);
return ret;
}
But in my main, when I pop them and try to compare them, I get a segmentation fault:
while ((data1 = my_stack_pop(s1))) {
data2 = my_stack_pop(fs1);
printf("Node of s1: (%d, %s)\t", data1->val, data1->name);
printf("Node of fs1: (%d, %s)\n", data2->val, data2->name);
if (!data2 || data1->val != data2->val || my_strcmp(data1->name, data2->name)) {
printf("Data in s1 and fs1 are not the same.\n (data1->val: %d <> data2->val: %d) o (data1->name: %s <> data2->name: "
"%s)\n",
data1->val, data2->val, data1->name, data2->name);
exit(1);
}
size1 = sizeof(*data1);
size2 = sizeof(*data2);
free(data1);
free(data2);
}
printf("size of data from s1: %d\t", size1);
printf("size of data from fs1: %d\n", size2);
(the 2 stacks are a copy of each other so what I inputed, should be the same I read). When I return the whole node in the pop function (not the data, but the whole my_stack_node), everything is right.. but wrong:
Comparing the data...
Node of s1: (0, Value 0) //good one
Node of fs1: (0, Value 0)
8
8
Node of s1: (-1203217792, NV) //here it begins to go all wrong
Node of fs1: (-1203217792, NV)
8
8
Node of s1: (-1203217792, NV)
Node of fs1: (-1203217792, NV)
8
8
Node of s1: (-1203217792, NV)
Node of fs1: (-1203217792, NV)
8
8
Node of s1: (0, )
Node of fs1: (0, )
double free or corruption (fasttop)
Aborted (core dumped)
Size is the same as the data inputed, but the value and name are bad (even in the non copied stack), which is supposed to be:
New node in s1: (0, Value 0)
New node in s1: (1, Value 1)
New node in s1: (2, Value 2)
New node in s1: (3, Value 3)
New node in s1: (4, Value 4)
New node in s1: (5, Value 5)
New node in s1: (6, Value 6)
New node in s1: (7, Value 7)
New node in s1: (8, Value 8)
New node in s1: (9, Value 9)
But when I return (on my stack pop) the data itself like in the code, I get core dumped in the print of the test.(data that has 8 bytes of length, like the one input).
When I return the node (size = 64) it prints correctly wrong data, but when I return the data(size = 8 (like the one pushed)), it core faults.
If I push the same data and read the same data (as it shown when I return node because even when weird output, are the same), why do I get a core segmentation fault when I return the data that's supposed to print like the example above?
It looks that it only happens when I read the data2, and not data1. This is the code I use to write and read the file :
Write:
int my_stack_write(struct my_stack *stack, char *filename){
int count = 0;
struct my_stack_node *aux =malloc(sizeof(struct my_stack_node));
FILE *file = fopen(filename, "wb");
if(stack->first != NULL){
aux = stack->first;
count++;
while(aux->next != NULL){
printf("New node in s1: (%p)\n", aux->data);
fwrite(aux ,sizeof(struct my_stack_node), 1, file);
aux = aux->next;
count++;
}
printf("New node in s1: (%p)\n", aux->data);
fwrite(aux ,sizeof(struct my_stack_node), 1, file);
}
fclose(file);
return count;
}
Read:
struct my_stack *my_stack_read(char *filename){
struct my_stack *stackRead = my_stack_init(sizeof(struct my_stack_node));
struct my_stack_node *stackNode = malloc(sizeof(struct my_stack_node));
FILE *file = fopen(filename, "rb");
if(!file){
puts("Impossible obrir el fitxer");
return NULL;
}else{
while(fread(stackNode, sizeof(struct my_stack_node), 1, file)){
printf("New node in fs1: (%p)\n", stackNode->data);
stackNode = (struct my_stack_node*) stackNode;
my_stack_push(stackRead, stackNode->data);
}
fclose(file);
struct my_stack *InvertedStack = my_stack_init(sizeof(struct my_stack_node));
struct my_stack_node *aux = malloc(sizeof(struct my_stack_node));
while(my_stack_len(stackRead) !=0){
printf("Inverting the stack\n");
aux = my_stack_pop(stackRead);
my_stack_push(InvertedStack, aux);
}
return InvertedStack;
}
}
Thank you to anyone that helps.
MCVE of the program, so people can check the whole code and help better:
test2.c:
https://codeshare.io/244eN4
my_lib.c:
https://codeshare.io/G7L8Ab
my_lib.h:
https://codeshare.io/5DzZOm
With this, you should have a broader view and an executable once compiled on what's happening to me.
you have problems in my_stack_pop
void *ret = malloc(sizeof(struct my_stack_node));
ret = node->data;
The malloc is useless (and create a memory leak), and you miss to free node too
You can replace these 2 lines by :
void * ret = node->data;
free(node);
Other remarks
in my_stack_push check the error before to do the allocation, or free nodeToPush in case of the error else you have a memory leak
sizeof(x) where x is a void* will always values 4 if you are on a 32b CPU, and 8 if it is a 64b CPU. sizeof is not strlen for instance
Finally concerning the 2 stacks are a copy of each other so what I inputed, should be the same it is difficult to help you because you do not say how you cloned the stack
(remarks after your edit)
In my_stack_write
do not initialize aux with an allocation, you again have a memory leak doing that.
to dump the memory of my_stack_node do not work, your goal is to save the data (contains of my_data), not the cell pointing to the data
In my_stack_read
it is useless to use a dynamic allocation for my_stack_node, it can be placed into the stack ( struct my_stack_node stackNode; ), else do not forget to free it because you again introduce a memory leak.
same error when you read a my_stack_node, you have to read the saved data (a my_data)
stackNode = (struct my_stack_node*) stackNode; that does nothing because it sets stackNode with itself
my_stack_push(stackRead, stackNode->data); does not have the expected result because stackNode->data has a wrong value read in the file.
Both read and write are wrong, this is why the two stack do not have the same contents
Designing good, reliable and consistent API and libraries is a very hard job, especially in programming languages in which creating interfaces is somewhat harder then in object oriented languages.
I mean to be really nice, but the code you posted has memory leaks, unhandled errors, undefined behavior and bad design. The sizeof operator is misused. I can only guess you fail to understand how the memory allocation really works and the concept of a pointer and general void* pointer.
Well, let's go.
So the reasons the code will seg fault is:
As suspected, the data to which the stack points is invalid. Indeed it is mallocated, but is subsequently freed some lines later:
for (int i = 0; i < NODES; i++) {
struct ... * data = malloc(sizeof(struct my_data));
my_stack_push(s1, data); // pushes the data pointer to the stack
void *data1 = my_stack_pop(s1); // pops the data pointer to the stack
...
assert(data1 == data); // data and data1 are the same
free(data1); // and data get's freed
// the memory behind both data and data1 is freed in this point
// thus the pointer s1.first->node->data is invalid
// as the code runs in loop, effectively all the data in this stack are invalid
}
You double free pointer in the main() in the while loop. Both s1 and fs1 are obtained from calling my_stack_read on the same file - thus logically they should contain the same values. As they store the same values, stored pointers to data are the same, thus freeing the pointer will also free and invalidate the second pointer in the second list. Double free is undefined behavior and I guess should result in something similar to segmentation fault on normal systems.
while ((data1 = my_stack_pop(s1))) {
data2 = my_stack_pop(fs1);
...
assert(data1 == data2); // same pointers
free(data1);
free(data2); // double free corruption - seg fault
}
After fixing the errors the code will run and print "All tests passed", live version available here. Anyway below are some notes:
There is no need to allocate an array of stacks in my_stack_init:
struct my_stack *my_stack_init(int size){
struct my_stack *stack = malloc(sizeof(struct my_stack_node) * size);
...
stack now points to size count of sizeof(struct my_stack_node) bytes of memory. You need only a single my_stack_node structure. Also, sizeof returns size_t. A better version would be:
struct my_stack *my_stack_init(size_t size){
struct my_stack *stack = malloc(sizeof(struct my_stack_node));
...
my_stack_read leaks memory:
struct my_stack_node *aux = malloc(sizeof(struct my_stack_node));
...
aux = my_stack_pop(stackRead);
Indentation in the code you posted is a bit off. Try to keep one indentation style, I could advertise the good old' Linux kernel coding style but you can use anything but be consistent. Also your code could use some restructuring - limiting the scope of variables or like removing else after return NULL may increase readability.
sizeof returns size_t. The proper way to print size_t is to use "%zu" printf modifier. You can print pointers by casting to void* and using "%p" printf modifier.
Generally, this is really good work, but you need to understand that pointers point to data and are data themselves (as they have value). Currently your implementation stores only pointers to the data, thus client code is responsible for freeing the pointers. It's easy to trap yourself in confusion in such implementation. One could rewrite your stack implementation to allocate memory for the node and for the data itself, thus freeing the need for client code to handle the memory in any special manner. It could look like:
int my_stack_push(struct my_stack *stack, void *data) {
...
// allocate memory for new link in the list
struct my_stack_node *nodeToPush = malloc(sizeof(struct my_stack_node));
if (nodeToPush == NULL) abort();
// allocate memory for data itself
nodeToPush->data = malloc(stack->size);
if (nodeToPush->data == NULL) abort();
// memory copy the data into the pointer
memcpy(nodeToPush->data, data, stack->size);
..
In such implementation the stack is responsible in freeing the pointer and stores only copies of the data. Thus all the handles need to be rewritten to support that. The size of the data is available via stack->size and initialized in my_stack_init with the argument.
Storing pointers value in a file seems like a bad idea from serialization point of view. Pointer values change in between runs. Storing pointers to list elements feels exactly bad. It's better to store the memory of the data itself, I see no reason in storing the pointer values of the list. Note that in current implementation the value of stackNode->next is indeed not used in my_stack_read, because it's value has been freed already before. I fail to see why do you even write the value of stackNode->next to the file if you never use it.
So we can store the data itself in the file:
int my_stack_write(struct my_stack *stack, char *filename){
...
node = stack->first;
void *data = node->data;
// write the data behind the node to the file
if (fwrite(data, stack->size, 1, file) != 1) {
return -100;
}
}
In a similar way we could rewrite my_stack_read:
struct my_stack *my_stack_read(char *filename, size_t size) {
...
struct my_stack *stack = stack_init(size);
...
void *newdata = malloc(stack->size);
while (fread(newdata, stack->size, 1, file)) {
my_stack_push(stack, newdata);
}
free(newdata); // as in my proposed implementation my_stack stores copy
// of the memory behind the pointers, we can safely manage own memory
// by freeing the pointer
}
Related
I have a block of pointers to some structs which I want to handle (i.e. free) separately. As an example below there is an integer double-pointer which should keep other pointers to integer. I then would like to free the second of those integer pointers (in my program based on some filterings and calculations). If I do so however, I should keep track of int-pointers already set free so that when I iterate over the pointers in the double-pointer I do not take the risk of working with them further. Is there a better approach for solving this problem (in ANSI-C) without using other libs (e.g. glib or alike)?
Here is a small simulation of the problem:
#include <stdio.h>
#include <stdlib.h>
int main() {
int **ipp=NULL;
for (int i = 0; i < 3; i++) {
int *ip = malloc(sizeof (int));
printf("%p -> ip %d\n", ip, i);
*ip = i * 10;
if ((ipp = realloc(ipp, sizeof (int *) * (i + 1)))) {
ipp[i] = ip;
}
}
printf("%p -> ipp\n", ipp);
for (int i = 0; i < 3; i++) {
printf("%d. %p %p %d\n", i, ipp + i, *(ipp+i), **(ipp + i));
}
// free the middle integer pointer
free(*(ipp+1));
printf("====\n");
for (int i = 0; i < 3; i++) {
printf("%d. %p %p %d\n", i, ipp + i, *(ipp+i), **(ipp + i));
}
return 0;
}
which prints something like
0x555bcc07f2a0 -> ip 0
0x555bcc07f6f0 -> ip 1
0x555bcc07f710 -> ip 2
0x555bcc07f6d0 -> ipp
0. 0x555bcc07f6d0 0x555bcc07f2a0 0
1. 0x555bcc07f6d8 0x555bcc07f6f0 10
2. 0x555bcc07f6e0 0x555bcc07f710 20
====
0. 0x555bcc07f6d0 0x555bcc07f2a0 0
1. 0x555bcc07f6d8 0x555bcc07f6f0 0
2. 0x555bcc07f6e0 0x555bcc07f710 20
Here I have freed the middle int-pointer. In my actual program I create a new block for an integer double-pointer, iterate over the current one, create new integer pointers and copy the old values into it, realloc the double-pointer block and append the new pointer to it, and at the end free the old block and all it's containing pointers. This is a bit ugly, and resource-consuming if there is a huge amount of data, since I have to iterate over and create and copy all the data twice. Any help is appreciated.
Re:
"This is a bit ugly, and resource-consuming if there is a huge amount of data, since I have to iterate over and create and copy all the data
twice. Any help is appreciated."
First observation: It is not necessary to use realloc() when allocating new memory on a pointer that has already been freed. realloc() is useful when needing to preserve the contents in a particular area of memory, while expanding its size. If that is not a need (which is not in this case) malloc() or calloc() are sufficient. #Marco's suggestion is correct.
Second observation: the following code snippet:
if ((ipp = realloc(ipp, sizeof (int *) * (i + 1)))) {
ipp[i] = ip;
}
is a potential memory leak. If the call to realloc()_ fails, the pointer ipp will be set to null, making the memory location that was previously allocated becomes orphaned, with no way to free it.
Third observation: Your approach is described as needing:
Array of struct
dynamic memory allocation of a 2D array
need to delete elements of 2D array, and ensure they are not referenced once deleted
need to repurpose deleted elements of 2D array
Your initial reaction in comments to considering using an alternative approach notwithstanding, Linked lists are a perfect fit to address the needs stated in your post.
The fundamental element of a Linked List uses a struct
Nodes (elements) of a List are dynamically allocated when created.
Nodes of a List are not accessible to be used once deleted. (No need to track)
Once the need exists, a new node is easily created.
Example struct follows. I like to use a data struct to contain the payload, then use an additional struct as the conveyance, to carry the data when building a Linked List:
typedef struct {//to simulate your struct
int dNum;
char unique_name[30];
double fNum;
} data_s;
typedef struct Node {//conveyance of payload, forward and backward searchable
data_s data;
struct Node *next; // Pointer to next node in DLL
struct Node *prev; // Pointer to previous node in DLL
} list_t;
Creating a list is done by creating a series of nodes as needed during run-time. Typically as records of a database, or lines of a file are read, and the elements of the table record (of element of the line in a file) are read into and instance of the data part of the list_s struct. A function is typically defined to do this, for example
void insert_node(list_s **head, data_s *new)
{
list_s *temp = malloc(sizeof(*temp));
//insert lines to populate
temp.data.dNum = new.dNum;
strcpy(temp.data.unique_name, new.unique_name);
temp.fNum = new.fNum
//arrange list to accomdate new node in new list
temp->next = temp->prev = NULL;
if (!(*head))
(*head) = temp;
else//...or existing list
{
temp->next = *head;
(*head)->prev = temp;
(*head) = temp;
}
}
Deleting a node can be done in multiple ways. It the following example method a unique value of a node member is used, in this case unique_name
void delete_node_by_name(list_s** head_ref, const char *name)
{
BOOL not_found = TRUE;
// if list is empty
if ((*head_ref) == NULL)
return;
list_s *current = *head_ref;
list_s *next = NULL;
// traverse the list up to the end
while (current != NULL && not_found)
{
// if 'name' in node...
if (strcmp(current->data.unique_name, name) == 0)
{
//set loop to exit
not_found = FALSE;
//save current's next node in the pointer 'next' /
next = current->next;
// delete the node pointed to by 'current'
delete_node(head_ref, current);
// reset the pointers
current = next;
}
// increment to next node
else
{
current = current->next;
}
}
}
Where delete_node() is defined as:
void delete_node(list_t **head_ref, list_t *del)
{
// base case
if (*head_ref == NULL || del == NULL)
return;
// If node to be deleted is head node
if (*head_ref == del)
*head_ref = del->next;
// Change next only if node to be deleted is NOT the last node
if (del->next != NULL)
del->next->prev = del->prev;
// Change prev only if node to be deleted is NOT the first node
if (del->prev != NULL)
del->prev->next = del->next;
// Finally, free the memory occupied by del
free(del);
}
This link is an introduction to Linked Lists, and has additional links to other related topic to expand the types of lists that are available.
You could use standard function memmove and then call realloc. For example
Let's assume that currently there are n pointers. Then you can write
free( *(ipp + i ) );
memmove( ipp + i, ipp + i + 1, ( n - i - 1 ) * sizeof( *pp ) );
*( ipp + n - 1 ) = NULL; // if the call of realloc will not be successfull
// then the pointer will be equal to NULL
int **tmp = realloc( ipp, ( n - 1 ) * sizeof( *tmp ) );
if ( tmp != NULL )
{
ipp = tmp;
--n;
}
else
{
// some other actions
}
So for my C assignment, I need to implement a dynamic memory allocator with a similar interface to the standard library like malloc, free, realloc. I'm implementing the allocator as a library of functions that can be called by other programs. Virtual heap will be managed by a simple buddy allocation algorithm.
My functions given are:
void * virtual_sbrk(int32_t increment);
pretty much the same as the real-world sbrk and brk syscalls. I don't need to implement this.
void init_allocator(void * heapstart, uint8_t initial_size, uint8_t min_size);
This function will be called once at the beginning and initialise the virtual heap.
void * virtual_malloc(void * heapstart, uint32_t size);
mallocs memory
int virtual_free(void * heapstart, void * ptr);
frees memory
void * virtual_realloc(void * heapstart, void * ptr, uint32_t size);
reallocates memory
void virtual_info(void * heapstart);
prints the current state of the buddy allocator to standard output.
This is my current problem:
How do you initialise the heap and implement malloc without anything in the first place? Like I can't use malloc or any of the pre existing allocator functions. So far I've tried to use a linked list with nodes containing the memory as a value. Eg if initial size is 3 and min size is 1, I'd have 5 nodes with the root containing 8 bytes, two more containing 4 bytes each , and lastly 2 more contining 2 bytes each. But I'm still confused on how to use sbrk or how the heap is structured in the first place. I've browsed online resources but still confused on how to construct the heap memory.
Following is my code so far:
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
struct node{
size_t memory;
struct node *nextInLine;
};
void printNode(const struct node *nd, const char *comment){
if(nd == NULL){
printf("%s is null\n", comment);
}
else{
printf("%s: memory:%d address:%p nextInLine:%p\n",
comment,
nd->memory,
nd,
nd->nextInLine);
}
}
void printList(const struct node *list){
printf("Printing List:\n");
const struct node *t;
t = list;
if(t == NULL){
printf("current node is empty\n");
}
else{
while(t){
printNode(t, "node");
t = t->nextInLine;
}
}
}
void * virtual_sbrk(int32_t increment) {
void *p = malloc(increment);
return p;
}
uint8_t return_init_size(uint8_t size){
return size;
}
struct node *getNewNode(const uint8_t memory_size){
struct node *newNode = NULL;
double two = 2;
size_t m_size = memory_size;
double result = pow(two, m_size);
newNode = virtual_sbrk(result);
if(newNode != NULL){
newNode->memory = result;
newNode->nextInLine = NULL;
}
else{
printf("Allocation error: newNode is still NULL\n");
}
return newNode;
}
void init_allocator(void * heapstart, uint8_t initial_size, uint8_t min_size) {
//error catchers
if(initial_size == 0){
printf("Initial size is 0\n");
}
if(initial_size < min_size){
printf("initial_size is smaller than min_size\n");
}
//initialising the virtual heap using a linked array with nodes the memory size of 2^some_size
uint8_t i = initial_size;
struct node *first = heapstart;
heapstart = first;
struct node *tail = NULL;
while(i >= min_size){
if(first == NULL){
first = getNewNode(i);
if(first != NULL){
tail = first;
}
}
else{
tail->nextInLine = getNewNode(i);
if(tail->nextInLine != NULL){
tail = tail->nextInLine;
}
tail->nextInLine = getNewNode(i);
if(tail->nextInLine != NULL){
tail = tail->nextInLine;
}
}
i -= 1;
}
printList(first);
}
void * virtual_malloc(void * heapstart, uint32_t size) {
if(size == 0){
return NULL;
}
return NULL;
}
int virtual_free(void * heapstart, void * ptr) {
return 1;
}
void * virtual_realloc(void * heapstart, void * ptr, uint32_t size) {
return NULL;
}
void virtual_info(void * heapstart) {
}
It would be great if someone could help explain how I would go about doing this, as in the structure I need to follow, if that makes sense.
You can use both sbrk and mmap as glibc malloc does.
glibc malloc works with threads, with something called arenas.
When malloc is initialized it calls sbrk to extend the mapped memory.
When big allocations happen, or new threads are created malloc ends up calling mmap.
mmap allocates a new mapping in the address space of the process.
sbrk extends the current mapping to make it bigger.
Simple example of sbrk:
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#define HEAP_SZ 0x8000
int main(void) {
void *p = sbrk(0);
printf("current break addr = %p\n", p);
sbrk(HEAP_SZ);
void *n = sbrk(0);
printf("new break addr = %p\n", n);
return 0;
}
The first call (with argument 0) returns the current program break.
When specifying a size greater than 0, program break is extended, so on the next call with argument 0, the new program break will be returned.
You can do then something like this:
unsigned long heap_mem_sz = 0;
void *heap_start_addr = NULL;
void init_heap(void) {
void *p = sbrk(0);
#if DEBUG
printf("current break addr = %p\n", p);
#endif
sbrk(HEAP_SZ);
heap_mem_sz = (unsigned long)HEAP_SZ;
void *n = sbrk(0);
#if DEBUG
printf("new break addr = %p\n", n);
#endif
heap_start_addr = (void *)n;
return;
}
Having that information on globals allows you to continue the development of the allocator implementation.
You can call init_heap() the first time an allocation is requested.
Now you can return that allocation and craft a "top chunk".
It will be a chunk with the same structure than the others but containing all the memory from which allocations take memory, and it gets shrinked on allocations.
Also, you will need to do something once the heap memory is full, so consider calling syscalls like mmap or sbrk again.
Linked lists on malloc are used for bins. They are used for searching freed chunks that can satisfy new allocations so you reuse chunks that are not used anymore.
For such linked list, you can create a global:
struct heap_chunk *freed_chain = NULL
When memory is requested, you first check if freed_chain is NULL, if not, traverse the linked list until a block compatible with the user request is found, or the next pointer is NULL.
If any of those chunks is valid, you will need to unlink that chunk from the linked list, and make the previous chunk point to the next one, so no more memory requests access to it as now it is allocated and not freed.
On freeing memory, you would need to link a new chunk to that linked list.
Obviously on malloc, for optimization purposes this is more complex, and some different bins with different size requirements and different properties exist to speed up allocations.
I'm doing an exercise, and want support about it. The problem is this: I have two structures (1 for the nodes of the stack, 1 for the stack). In the node structure, there is a void* data field.
I've tried to push a value on the stack but, because of void* data instead of simple data, I failed.
This is the code about the structures and the push() function.
struct upo_stack_node_s
{
void *data;
struct upo_stack_node_s *next;
};
typedef struct upo_stack_node_s upo_stack_node_t;
struct upo_stack_s
{
upo_stack_node_t *top;
size_t size;
};
/*Function for create the stack*/
upo_stack_t upo_stack_create()
{
upo_stack_t stack = malloc(sizeof(struct upo_stack_s));
if (stack == NULL)
{
fprintf(stderr, "Unable to create a stack!\n");
abort();
}
stack->top = NULL;
stack->size = 0;
return stack;
}
/*Push() function:*/
void upo_stack_push(upo_stack_t stack, void *data)
{
/* TO STUDENTS:
* Remove the following two lines and put here your implementation
*/
upo_stack_node_t *node = malloc(sizeof(struct upo_stack_node_s));
node->data = data; /*<-- Here's the problem */
node->next = stack->top;
stack->top = node;
++stack->size;
}
/*Top() function*/
void* upo_stack_top(const upo_stack_t stack)
{
/* TO STUDENTS:
* Remove the following two lines and put here your implementation
*/
return (void *)(stack->top); //<---
}
/*Function for testing (there are other functions in the code)*/
void test_top()
{
int value1 = 1;
int value2 = 2;
upo_stack_t stack;
stack = upo_stack_create();
upo_stack_push(stack, &value1); //<----
upo_stack_push(stack, &value2); //<----
assert( upo_stack_top(stack) != NULL );
assert( *((int*) upo_stack_top(stack)) == value2 ); <-- Here's the error
upo_stack_pop(stack, 0);
assert( upo_stack_top(stack) != NULL );
assert( *((int*) upo_stack_top(stack)) == value1 );
upo_stack_pop(stack, 0);
assert( upo_stack_top(stack) == NULL );
upo_stack_destroy(stack, 0);
}
You always have to pass a void pointer. That means if you want to pass a simple value, like 1, what you need to do is, is to allocate an integer value, and pass the pointer to it (as a void pointer).
Thus something like:
int x = 4;
upo_stack_push(upo_stack, &x);
Of course you have to make sure the int variable x does not go out of scope, otherwise the pointer will point to freed memory, which results in nasty memory problems.
Update
It is assumed above, that the void pointer you pass is stored already in memory for the scope of the stack. In case, you want the stack itself to copy the data, you have also to malloc space for that, thus not only mallocing the node, but also mallocing and copy the data type passed. Also to know the size of the data (since it is a void pointer, which is unaware of its type), you have to add an int size parameter to the push function.
For an integer value to be stored, pass it as a pointer, with size: sizeof(int). Than for copying the data structure, use memcpy. This only works for simple types and structures without pointers. If you have to copy structures with pointers (thus you need so called deep-copying), than it is more tricky.
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;
}
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 = #
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.