I am new to C, now I am making a linked list for face detection.
Below is the struct and the method for appending face at the end of linked list.
//Structure for storing a face with x, y and window size
typedef struct Face {
int window;
int x;
int y;
struct Face* next;
} Face;
//Append face(window, x, y) to the end of linked list starting from head
void push(Face* head, int window, int x, int y) {
Face* temp = (Face *)malloc(sizeof(Face));
temp->window = window;
temp->x = x;
temp->y = y;
temp->next = NULL;
Face* cur = head;
if (head == NULL) {
printf("Called\n");
head = temp;
} else {
while (cur->next != NULL) {
cur = cur->next;
}
cur->next = temp;
}
}
In another file, the executable, I called push(head, 1, 2, 3)[head here is initialized to NULL].
Only "Called' is printed on the screen. And the head is still NULL in the executable when I examine the linked list.
I have no idea why the head is not updated, but when I have it in the same file, it seems to work fine.
It's a guessing game since you don't show the relevant code.
Luckily, it's quite easy to guess well in this case...
The parameter you pass into the function is of type Face * and you set it to a new value (the new struct you allocated). Unfortunately, you're not returning this value, nor are you making sure the input parameter is capable of "transferring" data back to the calling context. What you should do is:
void push(Face** head, int window, int x, int y) {
// all you code here...
*head = temp
// rest of code...
}
And when you call the function:
push(&head, 1, 2, 3);
if (head == NULL) {
printf("Called\n");
head = temp;
}
The assignment head = temp only modifies the local copy of the head pointer. So it is not propagated to the code that called push(). If head was NULL in the code that calls push(), then it will remain so.
You could for example return the list head, as in:
Face *push(Face* head, int window, int x, int y) {
Face* temp = (Face *)malloc(sizeof(Face));
temp->window = window;
temp->x = x;
temp->y = y;
temp->next = NULL;
Face* cur = head;
if (head == NULL) {
printf("Called\n");
head = temp;
} else {
while (cur->next != NULL) {
cur = cur->next;
}
cur->next = temp;
}
return head;
}
And then use it like this:
/* ... */
head = push(head, window, x, y);
/* ... */
Another alternative is to pass a pointer to pointer to head (Face **), and replace that assignment with *head = temp;, but if you're a beginner I'd stick to the previous approach (and in my opinion, using double indirection is not necessary in most of the cases, but this can be subjective).
Finally, you might want to handle possible malloc(3) errors: the allocation can fail, you should check and handle that case.
I believe it is because you are passing in the value of the pointer head, which creates a copy of the pointer. By setting head to another address, you're not modifying head outside of scope, but rather the head within the method scope.
You'd need to pass in a pointer to the pointer to change it.
Function parameters are local variables of function. They are copies of the arguments. So the function parameter head is a copy of the argument head. Any changes of the parameter (of the copy of the argument) does not influence on the argument. You have to pass the head by reference.
Define the function the following way
//Append face(window, x, y) to the end of linked list starting from head
void push( Face **head, int window, int x, int y )
{
Face *temp = malloc( sizeof( Face ) );
if ( temp != NULL )
{
temp->window = window;
temp->x = x;
temp->y = y;
temp->next = NULL;
while ( *head ) head = &( *head )->next;
*head = temp;
}
}
And call the function like
push( &head, 1, 2, 3 );
Related
struct clist {
int pos;
char* color;
struct clist *next;
};
typedef struct clist sl_clist;
sl_clist *head = NULL;
sl_clist* link[5];
So i am trying to create multiple single linked circular lists and put them into a stack, every list will have the same types of data. In this case i am using the stack as an array. But i just cannot figure out how to create multiple linked lists from single type. I am a student so i am not very experienced on C. Thaks for the help in advance.
void create_list (int N, sl_clist* head){
int i;
sl_clist *new;
sl_clist *old;
if(N == 0){
head = NULL;
}
srand(time(0));
for(i = 0; i < N; i++){
new = (sl_clist*)malloc(sizeof(sl_clist));
if(i == 0){
head = new;
new -> color = color[(rand()%10)];
new -> pos = pos[i];
new -> next = head;
}
else{
new -> color = color[(rand()%10)];
new -> pos = pos[i];
old -> next = new;
new -> next = head;
}
old = new;
}
}
I have also tried creating multiple "head" variables but for some reason when i use them in this function(just imagine there are arrays for color and pos) they always return NULL.
Do not use global variables. Remove them.
sl_clist *head = NULL;
sl_clist* link[5];
Using local varaibles will "force" you to use a modular design that supports multiple lists.
Variables are passed by value:
head = new;
modifies a copy sl_clist* head of the original pointer passed as the argument. The original pointer is unaffected.
There are multiple ways you can solve that problem. You can return the new value:
sl_clist *create_list (int N, sl_clist* head){
...
return new; // or old value
}
int main() {
sl_clist *head = NULL;
head = create_list(5, head);
}
You can take the pointer by reference:
int create_list (int N, sl_clist **head){
...
*head = new; // set new value
(*head)->something = something; // be aware of operator precedence
}
int main() {
sl_clist *head = NULL;
create_list(5, &head); // head is getting modified
}
But I recommend doing a separate type for the head. That way the function is clear - it takes the head, specifically, not any list element. Be verbose:
struct sl_head {
struct clist *head;
};
int create_list(int N, struct sl_head *head) {
// ^^^^^^^^^^^^ - verbose, this is the head, not some element, less mistakces
head->head = new; // a bit more to type
head->head->something = something;
}
int main() {
struct sl_head head = {0}; // no longer a pointer
create_list(5, &head); // head is getting modified
}
Move srand(time(0)); to main(). It's not a function that you call when creating a list.
I have this C function which is supposed to find an element in the linked list which has a specific "pos" value, delete it, and return the deleted value to the calling function. It does delete the item, but the change isn't saved in the calling function, the list just doesn't get updated with the new changes.
My list is structured like this:
struct list{
int value;
int pos;
struct list * next_ptr;
};
And my C function is this:
bool findDeleteElement(struct list **ptr, int position, int *value){
struct list** temp = ptr;
if(*ptr!=NULL){
while((*ptr)->pos!=position) ptr=&(*ptr)->next_ptr; //Gets to desired node
temp=ptr;
value=&(*ptr)->value; //saves the value
temp=&(*temp)->next_ptr; //Goes to next node
ptr=temp; //Makes ptr point to next node
return 1;
}
else return 0;
}
I just can't see what I'm missing.
I'm a beginner so I probably made a simple mistake.
Change to:
*value = (*ptr)->value; //saves the value
You only set value, the local copy of your external variable's address. This does not change your external variable in the calling function.
Some question:
What happens when position has the wrong value, such that no node is found?
What's the purpose of temp = ptr;, because temp is overwritten by temp = &(*temp)->next_ptr; without having been used.
Disclaimer: I've not further checked this function.
I kindly advise you to take on other code formatting rules that add more air and make things more readable. Here's an example:
bool findDeleteElement(struct list **ptr, int position, int *value)
{
struct list** temp = ptr;
if (*ptr != NULL)
{
// Gets to desired node
while((*ptr)->pos != position)
{
ptr = &(*ptr)->next_ptr;
}
temp = ptr;
*value = (*ptr)->value; // Saves the value
temp = &(*temp)->next_ptr; // Goes to next node
ptr = temp; // Makes ptr point to next node
return 1;
}
else
{
return 0;
}
}
You are confused about pointers and dereferencing and what & and * actually do. This is a normal state of affairs for a beginner.
To start with, ptr and value when used without * preceding them are function arguments and like automatic (local) variables they disappear when the function scope exits. So this statement:
value=&(*ptr)->value;
Merely changes the value of value i.e. what it points to and has no visible effect to the caller. What you need to change is the thing that value points to. i.e. the statement should look like this:
*value = (*ptr)->value;
The difference is that instead of setting value to the address of (*ptr)->value it sets what valuepoints to to (*ptr)->value.
You have a similar problem with ptr. But your problems are more subtle there because you are also trying to use it as a loop variable. It's better to separate the two uses. I'd write the function something like this:
bool findDeleteElement(struct list **head, int position, int *value)
{
struct list* temp = *head;
struct list* prev = NULL;
while(temp != NULL && temp->pos != position)
{
prev = temp;
temp = temp->next;
}
if (temp == NULL) // position not found
{
return false;
}
else
{
*value = temp->value;
// Now need to delete the node.
if (prev != NULL)
{
// If prev has been set, we are not at the head
prev->next = temp->next; // Unlink the node from the list
}
else // We found the node at the head of the list
{
*head = temp->next;
}
free(temp); // Assumes the node was malloced.
return true;
}
}
The above is not tested or even compiled. I leave that as an exercise for you.
int delete(struct llist **pp, int pos, int *result)
{
struct llist *tmp;
while ( (tmp = *pp)) {
if (tmp->pos != pos) { pp = &tmp->next; continue; }
*result = val;
*pp = tmp->next;
free(tmp);
return 1;
}
return 0;
}
I'm writing a simple C program to manage a linked list defined as follow:
typedef struct node {
int value;
struct node *next;
} *List;
I reviewed the code and it seems okay but when printing results something is not working well.
My main, with problems on comments:
int main(void) {
List n = list_create(1);
insert(n, 2);
insert(n, 3);
insert(n, 5);
insert(n, 4);
//something here does not work properly. It produces the following output:
//Value: 1
//Value: 2
//Value: 3
//Value: 4
//where is value 5?
print_list(n);
delete(n, 3);
print_list(n);
return 0;
}
I don't know where am I destroying list structure. These are my functions, to debug, if you are too kind.
List list_create(int value) {
List new = malloc(sizeof(struct node));
new->value = value;
new->next = NULL;
return new;
}
List new_node(int value, List next_node) {
List new = malloc(sizeof(struct node));
new->value = value;
new->next = next_node;
return new;
}
void print_list(List l) {
List *aux;
for (aux = &l; (*aux) != NULL; aux = &((*aux)->next))
printf("Valor: %d\n", (*aux)->value);
}
void insert(List l, int value) {
List *p;
for (p = &l; (*p) != NULL; p = &((*p)->next))
if ((*p)->value > value) {
List tmp = *p;
List new = new_node(value, tmp);
*p = new;
break;
}
*p = new_node(value, NULL);
}
void delete(List l, int value) {
List *p;
for (p = &l; (*p) != NULL; p = &((*p)->next))
if ((*p)->value == value) {
List del = (*p);
(*p) = ((*p)->next);
free(del);
break;
}
}
This code has (at least) two bugs:
The line
if ((*p)->value > value){
means that if you start the list with 1 as the first value and then try to insert 2,3,4..., the body of the 'if' statement never runs, so nothing ever gets inserted.
If you insert a value below the starting value, you have to modify the list pointer itself. However, as #EOF alluded, you are trying to modify a value passed to a function by taking its address. This won't work. &l does not give you the address of the List you passed, it gives you the address of the local copy on insert()'s stack. You are better off modifying the values of first element of the list 'in place'. If you really want to make the List parameter mutable, you'll need to pass it as a List *, and call the function with the address of the list (e.g. insert(&n,2); ) Your delete() function suffers from the same problem - try deleting the first element of the list.
Try this for your insert function:
void insert(List l, int value)
{
List p;
// Find end of list or highest item less than value
for(p = l; p->next != NULL && p->next->value < value; p = p->next);
if (p->value >= value) {
// Over-write p with new value, and insert p as a new one after.
// This saves having to modify l itself.
int tmpval = p->value;
p->value = value;
p->next = new_node(tmpval, p->next);
} else {
// Insert new item after p
p->next = new_node(value, p->next);
}
}
A comment: it is possible the way you are using pointers is not helping the debugging process.
For example, your print_list() could be re-written like this:
void print_list(List l){
List aux;
for(aux = l; aux != NULL; aux = aux->next)
printf("Valor: %d\n", aux->value);
}
and still behave the same. It is generally good practice not to 'hide' the pointer-like nature of a pointer by including a '*' in the typedef.
For example, if you define your list like this:
typedef struct node{
int value;
struct node *next;
} List
And pass it to functions like this:
my_func(List *l, ...)
then it'll make some of these issues more apparent. Hope this helps.
There are many problems in your code:
Hiding pointers behind typedefs is a bad idea, it leads to confusion for both the programmer and the reader.
You must decide whether the initial node is a dummy node or if the empty list is simply a NULL pointer. The latter is much simpler to handle but you must pass the address of the head node to insert and delete so they can change the head node.
printlist does not need an indirect pointer, especially starting from the address of the pointer passed as an argument. Simplify by using the Node pointer directly.
in insert you correctly insert the new node before the next higher node but you should then return from the function. Instead, you break out of the switch and the code for appending is executed, replacing the inserted node with a new node with the same value and a NULL next pointer. This is the reason 5 gets removed and lost when you insert 4. Furthermore, you should pass the address of the head node so a node can be inserted before the first.
delete starts from the address of the argument. It cannot delete the head node because the pointer in the caller space does not get updated. You should pass the address of the head node.
You should avoid using C++ keywords such as new and delete in C code: while not illegal, it confuses readers used to C++, confuses the syntax highlighter and prevents compilation by C++ compilers.
Here is a simplified and corrected version:
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int value;
struct Node *next;
} Node;
Node *new_node(int value, Node *next_node) {
Node *node = malloc(sizeof(*node));
if (node != NULL) {
node->value = value;
node->next = next_node;
}
return node;
}
void print_list(Node *list) {
for (; list != NULL; list = list->next)
printf("Valor: %d\n", list->value);
}
void insert_node(Node **p, int value) {
while ((*p) != NULL && (*p)->value < value)
p = &(*p)->next;
*p = new_node(value, *p);
}
void delete_node(Node **p, int value) {
while (*p != NULL) {
if ((*p)->value == value) {
Node *found = *p;
*p = (*p)->next;
free(found);
// return unless delete() is supposed to remove all occurrences
return;
} else {
p = &(*p)->next;
}
}
}
int main(void) {
Node *n = NULL;
insert_node(&n, 2);
insert_node(&n, 3);
insert_node(&n, 5);
insert_node(&n, 4);
insert_node(&n, 1);
print_list(n);
delete_node(&n, 3);
print_list(n);
delete_node(&n, 1);
print_list(n);
return 0;
}
For a month or two since i started learning data-structures , using C, i have been following a particular method of writing linked list. Which looks like this.
#include<stdio.h>
#include<stdlib.h>
struct Node{
int exponent;
int coeff;
struct Node *next;
};
typedef struct Node N;
N *st = NULL;
void insert(N *node, int c, int e){
N *temp;
node->exponent = e;
node->coeff = c;
if(st == NULL){
node->next = st;
st = node;
} else {
temp = st;
while(temp->next != NULL){
temp = temp->next;
}
node->next = temp->next;
temp->next = node;
}
printf(" %p", st); //this is written on purpose, not that i write it everytime
}
and i call this from the main method,
N *node = malloc(sizeof *node);
insert(node, 1, 2);
The output of the printf for four such calls is
00340D18 00340D18 00340D18 00340D18
i.e the value of the start pointer remains constant, but if i make a small change in the code
typedef struct Node N;
void insert(N *node, N *st, int c, int e){
N *temp;
node->exponent = e;
node->coeff = c;
if(st == NULL){
node->next = st;
st = node;
} else {
temp = st;
while(temp->next != NULL){
temp = temp->next;
}
node->next = temp->next;
temp->next = node;
}
printf(" %p", st);
}
and declare the the start pointer in the main method
N *strt = NULL;
node = malloc(sizeof *node);
insert(node, strt, 1, 1);
then run this four times like in the previous case, the values of start pointer gets changed
after each call
00560D18 00560D30 00560D48 00560D60
Why does this happen?
And if i want to pass the start pointer as a parameter what changes should be made?
Why does this happen?
This happens because the change to st is invisible to the caller. That is st = node has no effect whatsoever for the caller. The function changes its own copy and after the function returns, if the caller prints strt, it will still be NULL.
This is a somewhat subtle consequence of the fact that in C arguments are passed by value, even pointers. So you pass strt by value. You can change st->whatever because it's a pointer and changes will propagate to the caller but changing strt itself will not work.
And if i want to pass the start pointer as a parameter what changes
should be made
This is a regular question on this site and there is also a C FAQ that describes the problem. A simple if somewhat cumbersome change that you can do is have the function take a
N **st and pass &strt.
This is because strt in your main method and st in the modified function insert are two different variables. The function call
insert(node, strt, 1, 1);
copies the value of strt which is defined in main to the function parameter st which is a different variable and is allocated on the stack when the function insert is invoked. Any changes made to st is visible inside the function only because it's a local variable. It goes out of scope once the function returns. Therefore, strt defined in main is still pointing to null and never gets changed. This means that the condition st == NULL is always true and the if block in insert is always executed and the local variable st is set to the newly created node each time the function insert is called. This would, in fact, cause memory leak because you lose the handle on the node once the function insert returns.
What you should do is to pass an address of the variable strt to insert so that the changes made to it is visible in main. Since you always append the new node at the end of the linked list, I suggest a few more changes.
void insert(N *node, N **st, int c, int e) {
N *temp = *st;
node->exponent = e;
node->coeff = c;
node->next = NULL; // set it explicitly to NULL
if(*st == NULL) { // if head of the linked list is NULL
*st = node;
}
else {
while(temp->next != NULL) // reach the end of the linked list
temp = temp->next;
temp->next = node; // add the new node at the end
}
printf("%p", *st);
}
And in main, invoke the function as
// in main method
N *strt = NULL;
node = malloc(sizeof *node);
insert(node, &strt, 1, 1);
typedef struct list
{
struct list * next;
int val;
}*list_t;
list_t add(list_t l,int e)
{
list_t head;
if(l == NULL)
{
l = malloc(sizeof(list_t));
l->val = e;
l->next = NULL;
return l;
}
head = l;
while(l != NULL)
l=l->next;
l = malloc(sizeof(list_t));
l->val = e;
l->next = NULL;
return head;
}
Sample driver:
int main()
{
list_t ints=NULL;
int i;
for(i=0;i<156;i+=2)
ints = add(ints,i);
while(ints->next != NULL)
{
printf("%d\n",ints->val);
ints=ints->next;
}
system("pause");
return 0;
}
Program works, but "add" function rewinds the list so that the body of main's loop is never achieved.It surprised me a lot, because I thought that I'd been passing list as a value! Could you explain this phenomenom?
The problem is not that the add function rewinds the list, is that it's not working at all: Nowhere in your code are you stating that the previous end of the list should link to the newly added element.
I've modified it slightly:
typedef struct list
{
struct list * next;
int val;
} list_t;
list_t *add(list_t *l,int e)
{
list_t *head;
if(l == NULL)
{
l = malloc(sizeof(list_t));
l->val = e;
l->next = NULL;
return l;
}
head = l;
while(l->next != NULL)
l=l->next;
l->next = malloc(sizeof(list_t));
l=l->next;
l->val = e;
l->next = NULL;
return head;
}
int main()
{
list_t *ints=NULL;
int i;
for(i=0;i<156;i+=2)
ints = add(ints,i);
while(ints->next != NULL)
{
printf("%d\n",ints->val);
ints=ints->next;
}
return 0;
}
The code now works as expected.
Remember that l is a local variable in the add function. Any changes made to l will be lost if it's not allowed to leave the scope of the function somehow (like you do when you return it, inside the first if). Changes made to the variable l points to, using either the * or the -> operators, will be effective to whoever has access to that variable.
I recomend that you start reading on debugging techniques. They vary depending on your environment, and can go from cryptic commandline tools like gdb to full-fledged graphical object browsers and such. This way you will be able to see what happens step by step and monitor memory changes and check what's really being stored in your variables.
EDIT: Fixed pointer trouble as commented. Memory allocations now provide for the whole struct variable, and pointers are no longer used implicitly.
Avoid the special cases. The add() function can do only one thing: allocate a list node and assign its pointer value to the first node in the chain that happens to be null. There is no difference between a NULL node at the head of the chain, in the middle, or at the tail. (of course null nodes cannot exist in the middle of the list. They can exist at the head of the list, but then the list would be empty) Find the first NULL and put the fresh node there.
struct list *add(struct list *lp, int e)
{
struct list **pp;
for (pp= &lp; *pp; pp = &(*pp)->next) {;}
*pp = malloc(sizeof **pp);
(*pp)->val = e;
(*pp)->next = NULL;
return lp;
}
l = malloc(sizeof(list_t));
that allocate a pointer to the struct, not the struct itself.
for example, on a 64 bit machine, the malloced size is 8, but it's supposed to be 16.
when you subsequently say
l->val = ..
l->next = ..
only God knows where you are writing to..
Go search some sample code of linked list, and read it through, I mean in the debugger.