how to keep a struct pointer outside a function in C [duplicate] - c

This question already has answers here:
Can someone help what is incorrect in this program? [duplicate]
(2 answers)
Closed 8 years ago.
I make a struct array in C and i want to initialize it in a void function. If i use return function it's well but if i use void function i have some problems.
Here is my code
#include <stdio.h>
#include <stdlib.h>
typedef struct Essai{
char *nom;
struct Essai* next;
} Essai;
void initialise(Essai* essai){
struct Essai *newE = malloc(sizeof(Essai));
newE->next = NULL;
printf("What's your name ? ");
scanf("%s", newE->nom);
if(essai != NULL){
essai = newE;
}else{
struct Essai* temp = essai;
while(temp->next != NULL) temp = temp->next;
temp->next = newE;
}
}
int main()
{
Essai *var = NULL;
initialise(var);
printf("nom : %s", var->nom);
return 0;
}
In the function essai is well created but outside the function it become NULL.

Remember that arguments to functions are passed by value, meaning that they are copied and the function only modifies the copy.
To make changes inside the function which is visible when the function returns, you need to emulate "call by reference", by passing a pointer. This includes passing pointers as pointer-to-pointer:
void initialise(Essai** essai){
...
*essai = newE;
...
}
int main(void)
{
Essai *var = NULL;
initialise(&var);
...
}
Another solution is to return the pointer from the function:
Essai *initialise(Essai* essai){
...
return essai;
}
int main(void)
{
Essai *var = NULL;
var = initialise(var);
...
}

Related

Why do I get a segmentation fault when trying to create a linked list using structures?

I am writing a code to create a linked list using structures in C language.
I have defined the structure with a data type and a pointer to structure type. Further I have used typedef to typecast this to Node_s.
I am using a function to initialise the first node; which basically won't contain any value but just returns the headpointer, which I will use to point to my next structure (node).
In the main block, I am initialising a structure pointer with Null value and then feeding the value from initialiser function to this pointer.
But this code is returning zsh: segmentation fault . Can someone explain me the issue!
#include <stdio.h>
#include <stdlib.h>
//Node* Initialize;
typedef struct Node {
int data;
struct Node* next;
} Node_s;
Node_s* Initialize(){
Node_s init_node;
Node_s* headlist;
init_node.data = 0;
init_node.next = headlist;
return headlist;
}
int main()
{
Node_s* ptr = NULL;
ptr = Initialize();
// 1st Node
ptr->data = 1;
Node_s* ptr2 = NULL;
ptr->next = ptr2;
// 2nd Node
ptr2->data = 1;
ptr2->next = NULL;
printf(" \n done deal %d", (*ptr2).data );
return 0;
}
main(): the variable ptr is uninitialized as returned from Initialize(). If it points to NULL or any other memory you don't have access to it will segfault when you deference it's members (ptr->data).
main(): the variable ptr2 is initialized to NULL, then you try to dereference it set its members. This will trigger a segfault if you get there.
Initialize(): init_node is a local variable and has no effect outside the function.
Initialize(): headlist is uninitialized as I mentioned above.
Initialize(): I suggest you change the signature to Node_s *Initialize(int data) so you can set the data to the value you need instead of a dummy value.
Here's a better starting point:
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node* next;
} Node_s;
Node_s *Initialize(int data) {
Node_s *headlist = malloc(sizeof(*headlist));
if(!headlist) {
printf("malloc failed\n");
return NULL;
}
headlist->data = data;
headlist->next = NULL;
printf("done deal %d\n", headlist->data);
return headlist;
}
int main() {
Node_s *ptr = Initialize(1);
if(!ptr)
return 1;
ptr->next = Initialize(2);
if(!ptr->next)
return 1
return 0;
}
The next step would be to eliminate the printf("done deal ...) statement in favor of a function that prints your linked list. Then write a function that frees the linked list. Then write a function that can Append(int data) an element to your list to replace Initialize().

Segmentation Fault doubly linked list with pointer [duplicate]

This question already has answers here:
How to change value of variable passed as argument?
(4 answers)
Closed 5 years ago.
The program has no problem in the push function as I can reach the members of the structure (e.g. key). If I call push(stack, 3) the key is 3 within the push function on the newElem pointer that has been allocated on the HEAP, but then when it is assigned to the stack, and used outside of push function (used in main), it no longer has a clue what values the members of the struct has at that current address. So it seems to me that the malloc doesn't really work and doesn't put the memory on the HEAP since It's not accessible anymore through the main function??
#include <stdio.h>
#include <stdlib.h>
typedef struct list_element_t {
int key;
struct list_element_t* next;
struct list_element_t* prev;
}ListElement;
ListElement* GetNewElement(int k) {
ListElement* newElem = (ListElement*) malloc(sizeof(ListElement));
newElem->key = k;
newElem->next = NULL;
newElem->prev = NULL;
return newElem;
}
void push(ListElement* S, int k) {
ListElement* newElem = GetNewElement(k);
//The key is always correct here
printf("%d\n", newElem->key);
if(S == NULL) {
S = newElem;
//S is not NULL here.
return;
}
newElem->next = S;
S->prev = newElem;
//Put our stack in the back of the list
S = newElem;
}
void display(ListElement* S) {
ListElement* temp = S;
while(temp != NULL) {
printf("%d\n", temp->key);
temp = temp->next;
}
}
int main(int argc, char **argv)
{
ListElement* stack = NULL;
push(stack, 3);
//stack is still NULL here????
//Causes segmentation Fault
printf("%d\n", stack->key);
//Never prints anything (stack is NULL)
display(stack);
return 0;
}
S in push function is local variable, so in this assigment
S = newElem;
you assign newElem to temporary object which is destroyed when push ends. If you want to modify content pointed by S you should pass this by pointer to pointer.
void push(ListElement** S, int k) {
ListElement* newElem = GetNewElement(k);
printf("%d\n", newElem->key);
if(*S == NULL) {
*S = newElem;
return;
}
newElem->next = *S;
(*S)->prev = newElem;
*S = newElem;
}
and in main function call push function as follows
ListElement* stack = NULL;
push(&stack, 3);

It seems like a printf makes my program bug [duplicate]

This question already has answers here:
How to access a local variable from a different function using pointers?
(10 answers)
Closed 5 years ago.
I am learning structures and linked-lists. However I am facing a problem that prevents me from debugging my program's bugs, since it comes, seemingly, from the function printf, which is what I use to debug the program.
The following program works fine:
struct pointer_struct
{
struct new_struct *ptr;
};
struct new_struct
{
int i;
struct new_struct *ptr;
};
void init(struct pointer_struct *pointer, int nb)
{
struct new_struct my_struct;
my_struct.i = nb;
my_struct.ptr = NULL;
pointer->ptr = &my_struct;
}
int main(void)
{
struct pointer_struct pointer;
pointer.ptr = NULL;
init(&pointer, 15);
//printf("pointer.ptr = %p\n", pointer.ptr);
printf("pointer.ptr->i = %d\n", pointer.ptr->i);
}
Output:
pointer.ptr->i = 15
But as soon as I uncomment the commented line, i takes weird values. Here are some examples of outputs:
$./a.out
pointer.ptr = 0x7fffc6bcc650
pointer.ptr->i = -448723664
$./a.out
pointer.ptr = 0x7fffd09ed480
pointer.ptr->i = 1218512176
$./a.out
pointer.ptr = 0x7ffff630fa70
pointer.ptr->i = -1073674960
What is going wrong with printf?
You have an undefined behavior or UB, which is always A Bad Thing™.
void init(struct pointer_struct *pointer, int nb)
{
struct new_struct my_struct;
my_struct.i = nb;
my_struct.ptr = NULL;
pointer->ptr = &my_struct;
} // here my_struct lifetime is finish so pointer->ptr become invalid
int main(void)
{
struct pointer_struct pointer;
pointer.ptr = NULL;
init(&pointer, 15);
printf("pointer.ptr = %p\n", pointer.ptr); // pointer.ptr is not valid so it's UB
printf("pointer.ptr->i = %d\n", pointer.ptr->i); // This is UB too
}
You initialize pointer.ptr with a local variable.
void init(struct pointer_struct *pointer, int nb)
{
struct new_struct my_struct;
my_struct.i = nb;
my_struct.ptr = NULL;
pointer->ptr = &my_struct; // MISTAKE!!! my_struct is on the stack.
// its memory space could be overwritten at
// any time after the function returns.
}
Later, in main
printf("pointer.ptr = %p\n", pointer.ptr); // This call to printf uses the stack,
// and overwrites the space used
// by my_struct
printf("pointer.ptr->i = %d\n", pointer.ptr->i);

Failed to add a node to linked list

I make the changes but
I can't add more than 2 nodes its will freez but if 1 or 2 node will work well what is the reason??? I gave_up
I can do nothing for that
This is my code till time
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
struct info{
int num;
char name[15];
struct info *next;
};
struct info *first,*current,*new_s;
int struct_num;
void add_struct(void);
int main(){
first=NULL;
add_struct();
puts("done");
add_struct();
puts("done");
add_struct();
puts("done");
return(0);
}
//struct add function
void add_struct(void){
new_s= malloc (sizeof(struct info));
if(!new_s){
puts("error");
exit (1);
}
if(first==NULL){
first = current= new_s;
first->next = NULL;
}else{
current=first;
while(current->next!=NULL){
current=current->next;
}
current->next=new_s;
current=new_s;
}
struct_num++;
}
The problem in your code is
if( first==NULL){
first->next=new_s;
if first is NULL, you should not dererefence it. It is logically wrong, and invokes undefined behaviour.
I think, what you want instead, is something like (pseudo-code)
if(first == NULL){
first = new_s;
first->next = NULL;
That said,
current->next=new_s;
current=new_s;
also looks problematic. The second statement there is wrong and not required, rather, you can add something like
current->next = new_s;
current->next->next = NULL;
Finally, your struct_num variable should be global, as per the current usage.
Note:
The recommended signature of main() is int main(void).
Please do not cast the return value of malloc() and family in C.
Always check for malloc() success before using the returned pointer.
Function add_struct is wrong
For example if first is equal to NULL then you may not write
first->next=new_s;
Take into account that there is no any sense to declare local variable of the function struct_num because it is always destroyed after exiting the function and moreover it even is not initialized in the function.
int struct_num;
If you need a count of nodes in the list then place it outside the function.
The function itself can look the following way
int struct_num;
int add_struct( void )
{
new_s = ( struct info * )malloc( sizeof( struct info ) );
if ( new_s == NULL ) return 0;
// initialize data members num and name of the allocated structure
new_s->next = NULL;
if ( first == NULL )
{
first = new_s;
}
else
{
current->next = new_s ;
}
current = new_s;
++struct_num;
return 1;
}

Adding and Finding node in LinkedList C

I have a small bug somewhere, was hoping someone with a little more C knowledge than I have to run through it real quick.
Im not certain if something is wrong in the map_put method or the map_get method, but I can only seem to map_get the first object in my list!?
anyhelp would be appreciated! thanks!
//----------------main---------------
#include <assert.h>
#include <stdio.h>
#include "map.h"
#include "map.c"
int main(){
map_t* newList = malloc(sizeof(map_t));
const char* passString ="a";
const char* secondString="2";
map_put(newList,"1","45");
map_put(newList,"3","3");
map_put(newList,"7","34");
map_put(newList,"a","45");
map_put(newList,"f","45");
map_put(newList,"2","45");
map_put(newList,passString,secondString);
map_get(newList, "3");
//printf("%d\n", map_size(newList));
printf("%1s\n", map_get(newList, "3"));
printf("%1s\n", map_get(newList, "1"));
printf("%1s\n", map_get(newList, "2"));
}
-----------------map.c----------------------
#include <assert.h>
#include "map.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
typedef int bool;
enum { false, true };
int size;
void map_init(map_t* self)
{
if(self==NULL)
self = (map_t*)malloc(sizeof(map_t));
self->entry = NULL;
self->size = 0;
}
int map_put(map_t* self, const char* key, const char* val)
{
assert(self != NULL);
//Create The Node Here For Storing Info;
struct _map_entry *node = (struct _map_entry *)malloc(sizeof(struct _map_entry));
node->key = (char *)key;
node->value = (char *)val;
node->next = NULL;
if(self==NULL)
{
map_init(self);
self->entry = node;
self->size = 1;
}
else
{
struct _map_entry *TempNode = self->entry;
if(TempNode==NULL)
{
TempNode = node;
self->entry = TempNode;
self->size = 1;
}
else
{
bool KeyExist = false;
while(TempNode->next != NULL)
{
if(strcmp(TempNode->key,node->key)==0)
{
KeyExist = true;
TempNode->value = node->value;
break;
}
TempNode = TempNode->next;
}
if(KeyExist)
{
return "Already Exists";
}
TempNode ->next = node;
self->size = self->size + 1;
}
}
}
const char* map_get(map_t* self, const char* key)
{
assert(self != NULL);
if(self==NULL)
return "";
struct _map_entry *StartNode = self->entry;
while(StartNode != NULL)
{
if(strcmp(StartNode->key,key)==0){
return StartNode->value;
}
else
StartNode = StartNode->next;
}
return "";
}
int map_size(map_t* self)
{
assert(self != NULL);
if(self==NULL)
return 0;
else
return size;
}
int map_remove(map_t* self, const char* key)
{
assert(self != NULL);
if(self==NULL)
return 0;
int totalRemovedNode = 0;
struct _map_entry *StartNode = self->entry;
struct _map_entry *TempNode = NULL;
while(StartNode != NULL)
{
if(strcmp(StartNode->key,key)==0)
{
struct _map_entry *Node = StartNode->next;
free(StartNode);
StartNode = TempNode;
TempNode = StartNode;
TempNode->next = Node;
size = size - 1;
totalRemovedNode = totalRemovedNode + 1;
}
StartNode = StartNode->next;
size = size - totalRemovedNode;
}
return totalRemovedNode;
}
void map_destroy(map_t* self)
{
assert(self != NULL);
struct _map_entry *StartNode = self->entry;
struct _map_entry *TempNode = NULL;
while(StartNode != NULL)
{
TempNode = StartNode->next;
free(StartNode);
StartNode = TempNode;
}
self->size = 0;
self->entry = NULL;
free(self);
}
int map_deserialize(map_t* self, FILE* stream)
{
assert(self != NULL);
assert(stream != NULL);
self->entry = NULL;
if(stream == NULL)
{
return 0;
// error
} else {
char *line = malloc(1024);
while(fgets(line,1024,stream))
{
char *value = strstr(line,":");
int keylength = value - line;
char *key = malloc(sizeof(keylength));
int i;
for(i = 0; i < keylength; i++)
{
key[i] = line[i];
}
key[keylength] = '\0';
value++;
map_put(self,key,value);
}
}
fclose(stream);
return self->size;
}
int map_serialize(map_t* self, FILE* stream)
{
assert(self != NULL);
assert(stream != NULL);
if(stream == NULL)
{
return 0;
}
struct _map_entry *it = self->entry;
while (it != NULL)
{
fwrite (it->key, sizeof (it->key), 1, stream);
fwrite (":", 1, 1, stream);
fwrite (it->value, sizeof (it->value), 1, stream);
fwrite ("\r\n", 2, 1, stream);
it = it->next;
}
return self->size;
}
----------------------map.h---------------------------
#ifndef __A1_MAP_H__
#define __A1_MAP_H__
#include <stdio.h>
typedef struct _map_entry map_entry_t;
struct _map_entry {
char* key;
char* value;
map_entry_t* next;
};
typedef struct _map {
map_entry_t* entry;
int size;
} map_t;
// Part one functions.
void map_init(map_t*);
int map_put(map_t*, const char*, const char*);
const char* map_get(map_t*, const char*);
int map_remove(map_t*, const char*);
int map_size(map_t*);
void map_destroy(map_t*);
// Part two functions.
int map_serialize(map_t*, FILE*);
int map_deserialize(map_t*, FILE*);
#endif
---------------------------
General Notes
According to 9899:2011 section 7.1.3 Reserved Identifiers, "all identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use". The same section of the C standard also says "All identifiers that begin with an underscore are always reserved for use as identifiers with file scope in both the ordinary and tag name spaces".
Please note that "reserved" means "you aren't allowed to do it". This means that when you #define __A1_MAP_H__, you are treading on namespace that doesn't belong to you, which is always considered to be inadvisable. Similarly, your struct _map_entry and your struct _map are also treading on reserved namespace. Consider renaming all these symbols.
You should not be casting the value that is returned by the malloc() function. You do this, inconsistently.
You should not be using the assert() macro for normal error checking. The assert() function is for debug-level sanity checks during the development process, that can be safely excluded from the code in production builds.
map_init()
Your map_init() function is wrong. If you pass a NULL to the map_init() function it allocates storage for one map_t, and initializes it, but doesn't have any way of returning it to the caller, so that storage is leaked (lost) as soon as the function returns, and the caller doesn't get anything. You should rewrite this function either to require a valid object be passed to it, or to allow it to return a pointer to a newly allocated object.
map_put()
You declare and define the map_put() function as returning a value of type int, but the only code path that returns anything at all, returns a char *.Additionally, this function doesn't copy the strings that are passed to it, but you're passing it both string literals and strings that are allocated using malloc().
map_get()
HINT: What does this function return if the first node is a match? If the second node is a match? If no node is a match?
map_size()
Why is the function returning the value of a file-scope variable that is never properly initialized? Did you perhaps intend, instead, for it to return the value of one of the elements of the map_t structure?
map_remove()
This function is so seriously messed up, that all I can advise you to do is go back to whatever reference you're learning about linked lists from, and re-read it.
map_destroy()
You aren't free()ing the strings attached to each node. You can't, of course, because you aren't copying them in, in map_put(), but some of what you put in there was allocated with malloc(), so you're leaking memory here.
map_deserialize()
This function does an odd half-init of the map_t that's passed to it, and it does it before validating prerequisites.
You allocate storage for line only once, using malloc(), then proceed to pass pointers into the middle of that storage to map_put(), which just stores the pointers instead of copying them, so you're overwriting the value every time you read the next line.
You malloc() storage for key each time through the loop, but you're allocating one byte fewer than you need, so you're constantly writing into storage that you don't own, every time you null-terminate that key you've just copied.
map_serialize()
HINT: If you have a char *foo, what is sizeof(foo)? How does this differ from strlen(foo)?

Resources