Reputation: 15
What is the difference between
struct LinkedList *current = malloc(sizeof(struct LinkedList));
and
struct LinkedList *current;
where
struct LinkedList{
int data;
struct LinkedList *next;
}
When I was creating a LinkedList I couldn't achieve most of my desired outcomes with the latter LinkedList declaration.
Upvotes: 0
Views: 127
Reputation: 1765
What is the difference between
struct LinkedList *current = malloc(sizeof(struct LinkedList));
andstruct LinkedList *current;
?
The difference is that int the first case LinkedList
pointer is initialized and in the second it is not.
Note that in C
you declare a variable giving the name and the type. So in
struct LinkedList *current = NULL
you are declaring current
as being of type struct LinkedList*
For the compiler spaces are irrevelant in this line.
If current
is a pointer then *current
is an instance of such type, *current
is struct LinkedList
. This is called de-referencing of a pointer, and this is C
. But you are not declaring *current
.
Writing the way you did can be misleading to beginners, by mixing cause and consequence. This is the real thing:
struct LinkedList* current = NULL;
Then you see what current
is being declared to be.
LinkedList
struct LinkedList
{
int data;
struct LinkedList* next;
}
You can for sure name it LinkedList
and write a correct program around that, with an actual linked list. But it is not an abstraction for a linked list. It seems to be just a node of a possible linked list of int
.
A linked list is a collection of nodes. Possibly empty. And it has nothing to do with data. Each node by its turn contains or points to an unit of data, usually said to be a record.
If your description does not show that your code will be more complicated, less useful and harder to test. You will need loose pointers to beginning of lis, counters for size, sometimes pointers to the tail and so on.
Here follows a complete example using a list of strings, so you can see one way of writing and using a more generic list with some useful operations. And one that can be used on an on
list created
3 elements back-inserted
#2 elements in list.
head element: Element 000001
tail element: Element 000002
"Element 000001" [15]
"Element 000002" [15]
[-----]
3 elements inserted at front
#4 elements in list.
head element: Element 000004
tail element: Element 000002
"Element 000004" [15]
"Element 000003" [15]
"Element 000001" [15]
"Element 000002" [15]
[-----]
after multi insert
#18 elements in list.
head element: Element 000004
tail element: Overflow
"Element 000004" [15]
"Element 000003" [15]
"Element 000001" [15]
"Element 000002" [15]
"7" [1]
"8" [1]
"9" [1]
"10" [2]
"11" [2]
"12" [2]
"A" [1]
"list" [4]
"has" [3]
"nodes." [6]
"Not" [3]
"data" [4]
"Stack" [5]
"Overflow" [8]
[-----]
list deleted
main()
for this exampleint main(void)
{ // now test the multi insert
const char delim = ' ';
Info* temp = NULL;
List* my_list = so_create_list(); // a new list
for (int i = 0; i < 2; i += 1)
{
temp = so_factory_info();
so_insert_back(temp, my_list);
free(temp);
}
so_print_list(my_list, "\n3 elements back-inserted\n");
for (int i = 0; i < 2; i += 1)
{
temp = so_factory_info();
so_insert_front(temp, my_list);
free(temp);
}
so_print_list(
my_list, "\n3 elements inserted at front\n");
so_multi_insert(
my_list, delim, 3,
"7 8 9 10 11 12", "A list has nodes. Not data", "Stack Overflow");
so_print_list(my_list, "\nafter multi insert\n");
so_delete_list(my_list);
return 0;
}
List
is a list typedef struct
{
size_t size;
Node* tail;
Node* head;
} List; // a (possibly empty) list of nodes
This is a list. A list of nodes. Each List
has its size
, head
and tail
. metadata is the name of these things. So when you declare
List list_set[42];
You are declaring an array of 42 lists. Each one has its size, head and tail. This is called encapsulation and makes life easier.
List
typedef struct st_node
{
struct st_node* prev; // links
struct st_node* next;
Info* info; // data
} Node;
Each node is a link. We are building a linked lis after all. But each node has a pointer to some Info
thing. Generic. So it can be reused.
This is the data for the example, a mixed C/Pascal
string.
typedef struct
{
size_t length;
char* string;
} Thing;
typedef Thing Info;
What is Thing
is not important. Note here the key typedef
relating our present List
content with Info
: this is the way to reuse the List
code. The list is always of nodes of Info
. We just redefine Info
each time.
List
and Info
operationsInfo
thing can have pointers inside.So the list must own all is data. If we want the list to work for generic content nodes we need to know to copy a node, how to delete a note, and maybe how to display one n-screen, at least for testing.
We do not need to know how to create one, since when one uses a list of something it sure must have or know how to create something. A list if a list of existing things.
List* so_create_list();
List* so_delete_list(List*);
int so_insert_back(Info*, List*);
int so_insert_front(Info*, List*);
int so_print_list(List*, const char* msg);
This is just an example, so only these operations are implemented. See that there is no mention of Node
here. And the operations are defined in simple terms: only pointers. o insert data in a list we take a pointer to the data and a pointer to the list. The print operation accepts a title, useful in testing. See the code above.
These 2 helper functions
int so_line_insert(
const char* string, const char delim, List* list);
int so_multi_insert(
List* list, const char delim, const unsigned N, ...);
are useful for inserting words by line or by group into a list.
Info* so_copy_info(const Info*);
Info* so_delete_info(Info*);
Info* so_factory_info();
int so_print_info(Info*, const char* msg);
so_factory_info
is here just for generating data for testing. It returns strings like "Element NNNNNN" so we can test for a few records or for thousands of them. From the example: Info* temp = NULL;
List* my_list = so_create_list(); // a new list
for (int i = 0; i < 2; i += 1)
{
temp = so_factory_info();
so_insert_back(temp, my_list);
free(temp);
}
so_print_list(my_list, "\n3 elements back-inserted\n");
prints
list created
3 elements back-inserted
#2 elements in list.
head element: Element 000001
tail element: Element 000002
"Element 000001" [15]
"Element 000002" [15]
[-----]
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// info, node and list
typedef struct
{
size_t length;
char* string;
} Thing;
typedef Thing Info;
Info* so_copy_info(const Info*);
Info* so_delete_info(Info*);
Info* so_factory_info();
int so_print_info(Info*, const char* msg);
typedef struct st_node
{
struct st_node* prev; // links
struct st_node* next;
Info* info; // data
} Node;
typedef struct
{
size_t size;
Node* tail;
Node* head;
} List; // a (possibly empty) list of nodes
List* so_create_list();
List* so_delete_list(List*);
int so_insert_back(Info*, List*);
int so_insert_front(Info*, List*);
int so_print_list(List*, const char* msg);
//
// helpers to build a list
//
int so_line_insert(
const char* string, const char delim, List* list);
int so_multi_insert(
List* list, const char delim, const unsigned N, ...);
int main(void)
{ // now test the multi insert
const char delim = ' ';
Info* temp = NULL;
List* my_list = so_create_list(); // a new list
for (int i = 0; i < 2; i += 1)
{
temp = so_factory_info();
so_insert_back(temp, my_list);
free(temp);
}
so_print_list(my_list, "\n3 elements back-inserted\n");
for (int i = 0; i < 2; i += 1)
{
temp = so_factory_info();
so_insert_front(temp, my_list);
free(temp);
}
so_print_list(
my_list, "\n3 elements inserted at front\n");
so_multi_insert(
my_list, delim, 3,
"7 8 9 10 11 12", "A list has nodes. Not data", "Stack Overflow");
so_print_list(my_list, "\nafter multi insert\n");
so_delete_list(my_list);
return 0;
}
//
// helper functions:
//
#define ST_OUT 0
#define ST_IN 1
#define MAX_SIZE 255
//
// insert string into list, word by word
//
int so_line_insert(
const char* string, const char delim, List* list)
{
if (list == NULL) return -1;
char state = ST_OUT;
char a_word[1 + MAX_SIZE] = {0}; // buffer for word
Info data = {.length = 0, .string = (char*)&a_word};
data.length = 0;
Info* temp = NULL;
// break string into words and put on list
const char* p_in = string;
char* p_out = data.string;
while (*p_in != 0)
{
switch (state)
{
case ST_OUT: // out of word
if (*p_in == delim)
{ // not in word
++p_in;
}
else
{ // new word starting here
p_out = data.string;
*p_out = *p_in;
state = ST_IN;
data.length = 1;
++p_in;
++p_out;
}
break;
case ST_IN: // in a word
default: // in a word
if (*p_in == delim)
{ // end of word
*p_out = 0; // end string
temp = so_copy_info(&data);
so_insert_back(temp, list);
free(temp);
state =
ST_OUT; // in search for another
++p_in;
}
else
{ // just another letter
*p_out = *p_in;
data.length += 1;
++p_in;
++p_out;
}
break;
}; // switch(state)
}; // while()
// now *p_in == 0, end of line
if (state == ST_OUT) return 0;
// state was ST_IN and reached end of input
if (p_out == data.string) return 0; // was empty
// inserts last word into list
*p_out = 0;
temp = so_copy_info(&data);
so_insert_back(temp, list);
free(temp);
return 0;
}
int so_multi_insert(
List* list, const char delim, const unsigned N, ...)
{
if (list == NULL) return -1;
va_list args;
va_start(args, N);
for (size_t i = 0; i < N; i += 1)
so_line_insert(va_arg(args, char*), delim, list);
va_end(args);
return 0;
}
// list code
// data related functions
Info* so_copy_info(const Info* orig)
{
if (orig == NULL) return NULL;
Info* cp = malloc(sizeof(Info));
if (cp == NULL) return NULL;
cp->string = malloc(1 + orig->length);
if (cp->string == NULL)
{
free(cp);
return NULL;
}
strcpy(cp->string, orig->string);
cp->length = orig->length;
return cp; // returns the address of the copy
}
Info* so_delete_info(Info* del)
{
if (del == NULL) return NULL;
if (del->string != NULL) free(del->string);
free(del);
return NULL;
}
Info* so_factory_info()
{
Info* one = malloc(sizeof(Info));
if (one == NULL) return NULL;
static int len = 1;
one->string = malloc(30);
one->length =
1 + sprintf(one->string, "Element %06d", len);
++len;
return one;
}
int so_print_info(Info* info, const char* msg)
{
if (info == NULL) return -1;
if (msg != NULL) printf("%s", msg);
printf(
" \"%s\" [%llu]\n", info->string, info->length);
return 0;
}
// list related functions
List* so_create_list()
{
List* list = malloc(sizeof(List));
if (list == NULL) return NULL;
list->head = NULL;
list->tail = NULL;
list->size = 0;
fprintf(stderr, " list created\n");
return list;
}
List* so_delete_list(List* del)
{
if (del == NULL) return NULL; // no list
for (size_t i = 0; i < del->size; i += 1)
{ // delete nodes, 1 by 1
Node* save = del->head->next;
so_delete_info(del->head->info);
free(del->head);
del->head = save;
};
free(del); // delete list
fprintf(stderr, " list deleted\n");
return NULL;
}
// inserts 'info' at the tail of the list
int so_insert_back(Info* info, List* list)
{
if (list == NULL) return -1; // no list
Node* node = (Node*)malloc(sizeof(Node));
if (node == NULL) return -2; // no alloc
node->info = so_copy_info(info);
if (list->size == 0) // first node
{
node->next = NULL;
list->size = 1;
list->head = node;
list->tail = node;
return 0; // 1st node
};
node->next = NULL;
list->tail->next = node;
list->tail = node;
list->size += 1;
return 0;
}
// inserts 'info' at the head of the list
int so_insert_front(Info* info, List* list)
{
if (list == NULL) return -1; // no list
Node* node = (Node*)malloc(sizeof(Node));
if (node == NULL) return -2; // no alloc
node->info = so_copy_info(info);
if (list->size == 0)
{
node->next = NULL;
list->size = 1;
list->head = node;
list->tail = node;
return 0; // 1st node
};
node->next = list->head;
list->head = node;
list->size += 1;
return 0;
}
int so_print_list(List* list, const char* msg)
{
if (list == NULL)
{
printf("No valid list!\n");
return 0;
}
if (list->size == 0)
{
printf("list is empty\n");
return 0;
}
if (msg != NULL) printf("%s", msg);
printf(
"\
#%llu elements in list.\n\
head element: %s\n\
tail element: %s\n",
list->size, list->head->info->string,
list->tail->info->string);
Node* p = list->head;
for (size_t i = 0; i < list->size; i += 1)
{
so_print_info(p->info, NULL);
p = p->next;
}
printf("\n[-----]\n\n");
return 0;
}
Upvotes: 0
Reputation: 30
If you define a pointer, it doesn't have an address. But if you equal it with malloc
it has an address in memory with that size, and you can fill that addresses with some data.
If you use it without malloc
and fill it in, you will get segmentation error in run time.
Run this code to see the result:
#include <stdio.h>
#include <stdlib.h>
struct LinkedList{
int data;
struct LinkedList *next;
};
int main(int argc, char const *argv[])
{
struct LinkedList *current = malloc(sizeof(struct LinkedList));
current->data = 1;
printf("%d\n", current->data );
struct LinkedList *current1;
current1->data = 2;
printf("%d\n", current1->data );
return 0;
}
Upvotes: 1
Reputation: 223673
struct LinkedList *current;
defines an object named current
of type struct LinkedList *
and does not specify an initial value for it. If it appears outside a function, the object is initialized to a null pointer. if it appears inside a function, it is not initialized, and the object’s value is indeterminate.
struct LinkedList *current = malloc(sizeof(struct LinkedList));
defines an object named current
as above, calls malloc
to allocate enough memory for an object of type struct LinkedList
, and initializes current
with the return value of malloc
. This would normally appear inside a function, so that malloc
is executed during program execution.
When I was creating a LinkedList I couldn't achieve most of my desired outcomes with the 2nd mentioned code.
That is because current
was not pointing to reserved memory, so attempting to use it as a pointer did something bad.
Upvotes: 3