searching for an element inside a linked list c - c

So i have a header file with a linked list implementation with a structure, the problem is when i want to find if an element is already inside the linked list if i do all the steps in the main function it works, but if i do that in a seperate function it doesnt work and i dont know why.
Program:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "Listas_ligadas2.h"
/*
ident: val[0]
linha: val[1]
*/
void remove_esp(char str[]); // removes the first char of the scanned string beacuse its of being a ' '
int equipa_in(link_v head, char nome[]);// the function with the problem
void A(char equipa[],int val[],link_v headv);
//basically while c != x it applies the switch
int main()
{
char c;char nome[1023];
link_v head2 = NULL;
int valores[2] = {0,1};
while ((c = getchar())!= 'x') {
switch (c)
{
case 'A':
{
scanf("%1023[^:\n]",nome);
remove_esp(nome);
if (equipa_in(head2,nome) == 1)
{
printf("%d Equipa existente.\n",valores[1]);
valores[1]++;
}
else
{
head2 = insertEnd_v(head2,nome,valores);
valores[1]++;
}
break;
}
}
}
return 0;
}
int equipa_in(link_v head, char nome[])
{
link_v t;
for(t = head; t != NULL; t = t->next)
if(strcmp(t->v.nome,nome) == 0)
return 1;
return 0;
}
void remove_esp (char str[])
{
int i;
if (str[0] == ' ')
{
for (i = 0; str[i] != '\0'; ++i)
str[i] = str[i + 1];
}
}
So if i do it like that it works fine, but if i do it like this:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "Listas_ligadas2.h"
/*
ident: val[0]
linha: val[1]
*/
void remove_esp(char str[]); // removes the first char of the scanned string beacuse its of being a ' '
int equipa_in(link_v head, char nome[]);// the function with the problem
void A(char nome[],int valores[],link_v head2);
//basically while c != x it applies the switch
int main()
{
char c;char nome[1023];
link_v head2 = NULL;
int valores[2] = {0,1};
while ((c = getchar())!= 'x') {
switch (c)
{
case 'A':
{
scanf("%1023[^:\n]",nome);
remove_esp(nome);
A(nome,valores,head2);
break;
}
}
}
return 0;
}
int equipa_in(link_v head, char nome[])
{
link_v t;
for(t = head; t != NULL; t = t->next)
if(strcmp(t->v.nome,nome) == 0)
return 1;
return 0;
}
void remove_esp (char str[])
{
int i;
if (str[0] == ' ')
{
for (i = 0; str[i] != '\0'; ++i)
str[i] = str[i + 1];
}
}
void A(char nome[],int valores[],link_v head2)
{
if (equipa_in(head2,nome) == 1)
{
printf("%d Equipa existente.\n",valores[1]);
valores[1]++;
}
else
{
head2 = insertEnd_v(head2,nome,valores);
valores[1]++;
}
}
it doesnt work and i dont understand why.
header file:
#ifndef _Listas_ligadas2_
#define _Listas_ligadas2_
#include<stdlib.h>
#include<stdio.h>
#include <string.h>
typedef struct vit
{
int id;
char *nome;
int vit;
} vit;
typedef struct node_v
{
vit v;
struct node_v *next;
} *link_v;
//this function removes a certin char at a given index
void removechar_v(char *orig, int index, char *newStr)
{
if(!orig){};
if(!newStr){};
int i=0, j=0;
while (*(orig+i) != '\0')
{
if (i != index)
{
*(newStr+j) = *(orig+i);
j++;
i++;
}
else i++;
}
*(newStr+j) = '\0';
}
link_v NEW_vit(char *nome,int val[])
{
int i;
link_v x = (link_v) malloc(sizeof(struct node_v));
x->v.nome = (char*) malloc(sizeof(char)*(strlen(nome)+1));
strcpy(x->v.nome,nome);
x->v.vit = 0;
x->v.id = val[0];
x->next = NULL;
val[0]++;
return x;
}
link_v insertEnd_v(link_v head,char *nome,int val[])
{
link_v x;
if(head == NULL)
return NEW_vit(nome,val);
for(x = head; x->next != NULL; x = x->next)
;
x->next = NEW_vit(nome,val);
return head;
}
int length_v(link_v head)
{
int count=0;
link_v x;
for(x=head ; x!=NULL; x=x->next)
count++;
return count;
}
//prints the elements in the list and copies its name to another string because
//for some reason if i want to print t->v.nome and the nome is abc it prints abcc
void print_lista_v(link_v head,int val[])
{
link_v t;char *nnome;
for(t = head; t != NULL; t = t->next){
nnome = (char*) malloc(strlen(t->v.nome)*sizeof(char));
strcpy(nnome,t->v.nome);
removechar_v(nnome,strlen(t->v.nome)-1,nnome);
printf("%d %d %s %d\n",val[1],t->v.id,nnome,t->v.vit);
}
}
//after removing an element it puts the corresponding indexes of the list
void baixa_id_v(link_v head)
{
link_v t;int i;
i = 0;
for(t = head; t != NULL; t = t->next){
t->v.id = i++;
}
}
void FREEnode_v(link_v t)
{
free(t->v.nome);
free(t);
}
link_v delete_el_v(link_v head,char *nome)
{
link_v t, prev;
for(t = head, prev = NULL; t != NULL;
prev = t, t = t->next) {
if(strcmp(t->v.nome,nome) == 0) {
if(t == head)
head = t->next;
else
prev->next = t->next;
FREEnode_v(t);
break;
}
}
return head;
}
link_v lookup_v(link_v head, char *nome)
{
link_v t;
for(t = head; t != NULL; t = t->next)
if(strcmp(t->v.nome,nome) == 0)
return t;
return NULL;
}
#endif

I have had a go at copying and then compiling/running your code. Apart from a few typos (the code has a few references to link_char which I changed to link_v, I also declared char nome_jg[1023] and link_v head) it works for me.
I did have to write the following function:
void remove_esp (char str[])
{
int i;
if (str[0] == ' ')
{
for (i = 0; str[i] != '\0'; ++i)
str[i] = str[i + 1];
}
}
...this seems to be what the comment required of the function.
The issue might be with your implementation of remove_esp.

As has already been pointed out in the comments section, the problem is that the function main is passing a pointer to the head of the linked list by value to the function A. This means that the function A will have its own copy of the pointer to the head of the linked list. So any modification to this pointer in the function A will not change the pointer in the function main.
If you want the function main to receive an updated value of the pointer to the head of the linked list, then you must provide some way for the function main to receive this value. You have 3 options to accomplish this:
Change the prototype of the function 'A' to return the value of the new pointer to the head of the linked list.
Change the prototype of the function 'A' so that the pointer to the head of the linked list is passed by pointer instead of by value.
Store the pointer to the head of the linked list in a global veriable that will be used by both functions main and A.
Generally, I don't recommend option #3, as it is often bad programming style to use global variables. Option #1 is better, however using return values is not very flexible, because a function can only return one value. Therefore, the most flexible option would be option #2.
In order to implement option #2, you would have to change the function prototype from:
void A(char nome[],int valores[],link_v head2);
to:
void A(char nome[],int valores[],link_v *head2);
However, this is confusing, because link_v is already a pointer; it is a typedef for a struct node_v *. Threfore, a link_v * is actually a struct node_v **, so it is a double pointer. To make it clear that it is a double pointer, I will not use the link_v typedef, but will use struct node_v ** instead. Also, to make clear that it is a double pointer, I will also change the name of the variable by prefixing a "pp_", like this:
void A(char nome[],int valores[], struct node_v **pp_head2);
Now, you can rewrite the line
A(nome,valores,head2);
in the function main to the following:
A(nome,valores,&head2);
You are now passing the variable head2 by pointer and no longer by value, so that no copy of the variable is made. That way, any changes to this variable by the function A will also change the value of this variable in the function main.
However, since the head2 parameter of the function A is now a double pointer, it must be used differently inside that function. The line
head2 = insertEnd_v(head2,nome,valores);
must be changed to:
*pp_head2 = insertEnd_v(*pp_head2,nome,valores);
Please note that I had to add the * to dereference the double pointer once. I also had to change the variable name in that line, because I had changed the name of the function parameter.

Related

What is wrong with my replace string with another string or character using linked list

I have a linked list with many chars which I input from my input (what is the weather today?), to be replaced with another string (for example what replaced with how, so I get how is the weather today?).
But if the given words are right next to each other for example whatwhat, it will change to howwhat, disregarding the second part.
I think the problem is in the compare function, but I have no clue how to fix it, but the logic of replace should go like this:
If the words from my list and the needed word are the same, then proceed to iterate to the position where the next node of the word that should be changed (unwanted word) should be (pretty much the end of the word), then I create a new linked list with character with the wanted word, and connect temp to the start of the list and the next of the list to the position where the next character of the word that needs to be changed (unwanted word), which I found in the first loop.
Also don't roast my input() function, I know it is unsafe I just want to see what unsafe means with my own eyes, while I still have nothing to lose.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node {
int value_c;
struct node *next_c;
struct node *prev_c;
};
typedef struct node string;
int compare(string *head, char *word) {
int counter = 0;
string *temp = head;
for (int i = 0; i < strlen(word); i++) {
if (temp->value_c == word[i]) {
temp = temp->next_c;
counter++;
}
}
if (counter == strlen(word))
return 1;
else
return 0;
}
void print_c(string *head) {
while (head != NULL) {
printf("%c", head->value_c);
head = head->next_c;
}
}
void append_c(string **head, char thing) {
string *newNode = (string *)malloc(sizeof(string));
newNode->value_c = thing;
newNode->next_c = NULL;
if (*head == NULL) {
*head = newNode;
newNode->prev_c = NULL;
return;
}
string *temp = *head;
while (temp->next_c != NULL)
temp = temp->next_c;
temp->next_c = newNode;
newNode->prev_c = temp;
}
string *replace_all1(string *head, char *what, char *with_what) {
string *temp = head;
while (temp != NULL) {
printf("%c ", temp->value_c);
if (compare(temp, what) == 1) {
printf("%i ", 1);
printf("%c ", temp->value_c);
string *new = temp;
for (int i = 0; i < strlen(what) - 1; i++) {
new = new->next_c;
}
string *word = NULL;
for (int i = 0; i < strlen(with_what); i++) {
append_c(&word, with_what[i]);
}
string *word_temp = word;
while (word_temp->next_c != NULL) {
word_temp = word_temp->next_c;
}
word_temp->next_c = new->next_c;
if (temp->prev_c != NULL) {
temp->prev_c->next_c = word;
} else {
head = word;
print_c(head);
temp = word;
print_c(temp);
word->prev_c = NULL;
}
}
temp = temp->next_c;
}
printf("\n");
return head;
}
string *String(char *str) {
string *st = NULL;
int i = 0;
while (str[i] != '\0') {
append_c(&st, str[i]);
i++;
}
return st;
}
string *input() {
char *a = (char *)malloc(sizeof(char));
scanf("%[^\n]", a); //maximum of 1408
string *stri = String(a);
return stri;
free(a);
}
int main() {
string *list = NULL;
string *big_boy_string = input();
//printf("%c", big_boy_string->value_c);
//print_c(big_boy_string);
//printf("\n");
//printf("%i", compare(big_boy_string, "what"));
//printf("%i ", len(big_boy_string));
//printf("\n");
//print_c(slice(big_boy_string, 1, 10));
//print_c(replace(big_boy_string, 'h', 'a'));
//printf("\n");
//print_c(reverse(big_boy_string));
print_c(replace_all1(big_boy_string, "a", "b"));
//getline();
}
char *a = (char*) malloc(sizeof(char));
scanf("%[^\n]",a); //maximum of 1408
The first statement allocates memory for just 1 byte. So the maximum is not 1408, but 1. It can store a single char, or the null-terminator if it's a string, but no more.
Next, scanf() will write to out of bounds memory, and invoke undefined behaviour. The subsequent functions all depend on this undefined behaviour, so I'm not going to look at them.
But then, you've a memory leak in the same function.
return stri;
free(a);
You return before freeing the allocated memory. The call to free() is never executed.
The return value of malloc() is also ignored. Code risks undefined behaviour if the subsequent dereferences are on a NULL pointer.
Aside: The cast is meaningless and may hide a bug. malloc() and family returns a void * that is implicitly converted to the right type.
Re: Also don't roast my input() function, I know its unsafe I just
want to see what unsafe means with my own eyes.
If you are already aware of this, then you shouldn't be asking why your code doesn't work. You are relying on undefined behaviour (playing with fire).
There is no need to look further than the input function: it has undefined behavior or the worst kind because you attempt to read the input string into a very small array, allocated for a single byte. You must fix this first. Since you know the maximum length of your input string, you can use this:
string *input(void) {
char a[1409];
if (scanf("%1408[^\n]", a) != 1) { //maximum of 1408
// invalid or missing input
return NULL;
}
scanf(%*[^\n]"); // consume any remaining characters on the input line
scanf(%*1[\n]"); // consume the newline if present
return String(a);
}
Here is an alternative using getchar() instead of scanf() which is quite tricky and error prone:
string *input(void) {
char a[1409];
int c;
size_t i = 0;
while ((c = getchar()) != EOF && c != '\n') {
if (i + 1 < sizeof(a))
a[i++] = (char)c;
}
if (c == EOF && i == 0) {
/* end of file without any input */
return NULL;
}
a[i] = '\0';
return String(a);
}
The compare function is incorrect: it should return false as soon as the comparison fails and it must test for the end of string (temp == NULL):
int compare(const string *head, const char *word) {
string *temp = head;
for (size_t i = 0; word[i] != '\0'; i++) {
if (temp == NULL || temp->value_c != word[i])
return 0;
temp = temp->next_c;
}
return 1;
}
The replace_all1() function has problems too:
for (int i = 0; i < strlen(what) - 1; i++) will cause undefined behavior if what is an empty string because strlen(what) - 1 is unsigned with the value SIZE_MAX in this case, causing the loop to proceed for a very long time, well beyond the end of the list pointed to by new.
while (word_temp->next_c != NULL) will cause a undefined behavior if the replaced word is empty as word_temp will be NULL.
once you replace the sublist, you do not update temp correctly to point to the node after the replaced one, which you could achieve by setting temp to word_temp.
the function does not free the replaced sublist.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node {
int value_c;
struct node *next_c;
struct node *prev_c;
};
typedef struct node string;
void string_append_char(string **head, int c) {
string *node = malloc(sizeof(*node));
if (node == NULL) {
fprintf(stderr, "out of memory\n");
exit(1);
}
node->value_c = c;
node->next_c = NULL;
if (*head == NULL) {
node->prev_c = NULL;
*head = node;
} else {
string *temp = *head;
while (temp->next_c != NULL)
temp = temp->next_c;
node->prev_c = temp;
temp->next_c = node;
}
}
string *string_new(const char *str) {
string *st = NULL;
for (int i = 0; str[i] != '\0'; i++) {
string_append_char(&st, str[i]);
}
return st;
}
string *string_input(const char *prompt) {
string *st = NULL;
int c;
if (prompt) {
printf("%s", prompt);
}
while ((c = getchar()) != EOF && c != '\n') {
string_append_char(&st, c);
}
return st;
}
void string_print(const char *before, const string *head, const char *after) {
printf("%s", before);
while (head != NULL) {
putchar(head->value_c);
head = head->next_c;
}
printf("%s", after);
}
void string_free(string *head) {
while (head != NULL) {
string *next = head->next_c;
free(head);
head = next;
}
}
int string_compare(const string *head, const char *word) {
const string *temp = head;
for (size_t i = 0; word[i] != '\0'; i++) {
if (temp == NULL || temp->value_c != word[i])
return 0;
temp = temp->next_c;
}
return 1;
}
int string_replace(string **head, const char *what, const char *with_what) {
int count = 0;
if (*what == '\0')
return 0;
string *temp = *head;
while (temp != NULL) {
if (string_compare(temp, what)) {
count++;
// locate the last node of the substring
string *temp_end = temp;
for (size_t i = 0; what[i + 1] != '\0'; i++) {
temp_end = temp_end->next_c;
}
string *next = temp_end->next_c;
if (*with_what == '\0') {
// just delete the substring
if (temp->prev_c != NULL) {
temp->prev_c->next_c = next;
} else {
*head = next;
}
if (next) {
next->prev_c = temp->prev_c;
}
} else {
// create a string from the replacement
string *word = string_new(with_what);
// locate the last node of the new substring
string *word_end = word;
while (word_end->next_c != NULL) {
word_end = word_end->next_c;
}
word->prev_c = temp->prev_c;
if (temp->prev_c != NULL) {
temp->prev_c->next_c = word;
} else {
*head = word;
}
word_end->next_c = next;
if (next) {
next->prev_c = word_end;
}
}
temp_end->next_c = NULL;
string_free(temp);
temp = next;
} else {
temp = temp->next_c;
}
}
return count;
}
int main() {
string *list = string_input("enter string: ");
string_print("input: ", list, "\n");
printf("replacing 'what' to 'how': %d matches\n", string_replace(&list, "what", "how"));
string_print("rep1: ", list, "\n");
printf("replacing 'a' to 'b': %d matches\n", string_replace(&list, "a", "b"));
string_print("rep2: ", list, "\n");
printf("deleting 'h': %d matches\n", string_replace(&list, "h", ""));
string_print("rep3: ", list, "\n");
string_free(list);
return 0;
}
Sample session:
enter string: what is the weather today?
input: what is the weather today?
replacing 'what' to 'how': 1 matches
rep1: how is the weather today?
replacing 'a' to 'b': 2 matches
rep2: how is the webther todby?
deleting 'h': 3 matches
rep3: ow is te webter todby?

Segmentation fault when using advance function

Hi am trying to create a generic list iterator that stores elements of integer or string.I am trying to test a case where it calls the IteratorG advance(IteratorG it, int n) function which takes in the list it and if n is a positive integer,it advances(moves) towards the first element by n times.If n is negative,it advances towards the last element in the list by n times.The elements are then copied to a newly created list lis and the list returned.If advancing by n times is not possible,the function returns NULL.
This is tested in test case 3 under the test cases below.
However,it is responding with a segmentation fault error and i tried using gdp to diagnose the problem and i suspect it is from the advance function at the line add(lis,&(tem->value));
This is the advance function:
IteratorG advance(IteratorG it, int n){
int zero;
zero=0;
IteratorG lis;
lis = malloc(sizeof (struct IteratorGRep));
assert (lis != NULL);
lis->numofit = 0;
lis->head = NULL;
lis->tail = NULL;
lis->curr = NULL;
Node *tem;
if ((tem = malloc(sizeof(Node))) == NULL) {
return 0;
}
if(n<0 && distanceFromStart(it)!=0 )
{
for(tem=it->curr;n!=zero;it->curr=it->curr->prev)
{
add(lis,&(tem->value));
zero++;
}
return lis;
}
if(n>0 && distanceToEnd(it)!=0)
{
for(tem=it->curr;n!=zero;it->curr=it->curr->next)
{
add(lis,&(tem->value));
zero++;
}
return lis;
}
//To be implemented
//move forward by n times
return NULL;
}
I am using a Linux environment and the errors are indicative from the results. The rest of the functions that are required to test this(test in test case 3 under the test code) should be working fine.Here is the code for the whole program:
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include "iteratorG.h"
typedef struct Node {
void *value; // value of thee list item
struct Node *prev;
// pointer previous node in list
struct Node *next;
// pointer to next node in list
// implemented struct here ..
} Node;
typedef struct IteratorGRep {
int numofit; // count of items in list
Node *head; // first node in list
Node *curr; // current node in list
Node *tail; // last node in list
ElmCompareFp cmpElm;
ElmNewFp newElm;
ElmFreeFp freeElm;
// implemented struct here ..
} IteratorGRep;
/*
//Your functions below ....
*/
IteratorG newIterator(ElmCompareFp cmpFp, ElmNewFp newFp, ElmFreeFp freeFp){
IteratorG newit;
if ((newit = malloc(sizeof (struct IteratorGRep)))==NULL)
{
printf("Error...! \n");
}
//assert (newit != NULL);
newit->numofit = 0;
newit->head = NULL;
newit->tail = NULL;
newit->curr = NULL;
newit->cmpElm=cmpFp;
newit->newElm=newFp;
newit->freeElm=freeFp;
return newit;
// implemented function here and changed return value
}
int add(IteratorG it, void *vp){
Node *temp;
if ((temp = malloc(sizeof(Node))) == NULL) {
return 0;
}
Node *tempe;
if ((temp = malloc(sizeof(Node))) == NULL) {
return 0;
}
temp->value = it->newElm(vp);
//temp->next=NULL;
if(it->curr==NULL)
{
//temp->next=it->curr;
it->head=it->tail=temp;
it->curr=temp;
}
else
{
tempe=it->curr;
tempe->prev=temp;
temp->next=tempe;
it->curr=tempe;
it->curr=temp;
it->head=temp;
}
//it->tail=it->head=it->curr;
return 1;
}
int hasNext(IteratorG it){
if(it->curr->next==NULL)
{
return 0;
}
// check if theres next element/node
return 1;
}
int hasPrevious(IteratorG it){
if(it->curr->prev!=NULL)
{
return 1;
}
// check if theres previous element/node
return 0;
}
void *next(IteratorG it){
Node *tempo;
if(it->curr->next==NULL)
{
return NULL;
}
tempo=it->curr;
it->curr=it->curr->next;
// implemented function here
return tempo->value;
}
void *previous(IteratorG it){
Node *tempor;
tempor=it->curr;
if(tempor->prev==NULL)
{
return NULL;
}
tempor=it->curr->prev;
it->curr=it->curr->prev;
//tempor=it->curr;
// move to next node in list
return tempor->value;
}
int del(IteratorG it){
if(it->curr->prev!=NULL)
{
Node *temp_curr=it->curr;
Node *temp_prev=it->curr->prev->prev;
temp_curr->prev=temp_prev;
temp_prev->next=temp_curr;
return 1;
}// delete previous node from list
else
return 0;
}
int set(IteratorG it, void *vp){
if(it->curr->prev!=NULL)
{
it->curr->prev->value=vp;
return 1;
}
// change previous node value with new
return 0;
}
IteratorG advance(IteratorG it, int n){
int zero;
zero=0;
IteratorG lis;
lis = malloc(sizeof (struct IteratorGRep));
assert (lis != NULL);
lis->numofit = 0;
lis->head = NULL;
lis->tail = NULL;
lis->curr = NULL;
Node *tem;
if ((tem = malloc(sizeof(Node))) == NULL) {
return 0;
}
if(n<0 && distanceFromStart(it)!=0 )
{
for(tem=it->curr;n!=zero;it->curr=it->curr->prev)
{
add(lis,tem);
zero++;
}
return lis;
}
if(n>0 && distanceToEnd(it)!=0)
{
for(tem=it->curr;n!=zero;it->curr=it->curr->next)
{
add(lis,&(tem->value));
zero++;
}
return lis;
}
//To be implemented
//move forward by n times
return NULL;
}
void reverse(IteratorG it){
Node *curr = it->head;
Node *temp = NULL;
while(curr != NULL) {
temp = curr->next;
curr->next = curr->prev;
curr->prev = temp;
curr = temp;
}
temp = it->head;
it->head = it->tail;
it->tail = temp;// reverse elements of whole list
}
IteratorG find(IteratorG it, int (*fp) (void *vp) ){
// To be implemented
// Find elements of vp in list after current position and put in new list.return the list.
return NULL;
}
int distanceFromStart(IteratorG it){
Node *c=it->curr;
int count=0;
while(c->prev!=NULL)
{
c=c->prev;
count++;
}
return count;
// count number of elements from start of list to current position
}
int distanceToEnd(IteratorG it){
Node *cu=it->curr;
int count=0;
while(cu->next!=NULL)
{
cu=cu->next;
count++;
}
return count;
// count number of elements from end of list to current position
}
void reset(IteratorG it){
while(it->curr->prev!=NULL)
{
it->curr=it->curr->prev;
}
return;
// move current position to start of list
}
void freeIt(IteratorG it){
assert(it != NULL);
Node *curr, *prev;
curr = it->head;
while (curr != NULL) {
prev = curr;
curr = curr->next;
// free(prev->value);
free(prev);
}
free(it); // free items
}
This is the header file for the code:
#ifndef LISTITERATORG_H
#define LISTITERATORG_H
#include <stdio.h>
typedef struct IteratorGRep *IteratorG;
typedef int (*ElmCompareFp)(void const *e1, void const *e2);
typedef void *(*ElmNewFp)(void const *e1);
typedef void (*ElmFreeFp)(void *e1);
IteratorG newIterator(ElmCompareFp cmpFp, ElmNewFp newFp, ElmFreeFp freeFp);
int add(IteratorG it, void *vp);
int hasNext(IteratorG it);
int hasPrevious(IteratorG it);
void *next(IteratorG it);
void *previous(IteratorG it);
int del(IteratorG it);
int set(IteratorG it, void *vp);
IteratorG advance(IteratorG it, int n);
void reverse(IteratorG it);
IteratorG find(IteratorG it, int (*fp) (void *vp) );
int distanceFromStart(IteratorG it);
int distanceToEnd(IteratorG it);
void reset(IteratorG it);
void freeIt(IteratorG it);
#endif
One of the functions have yet to be implemented and is indicated in the code itself. But I guess that might not be the source of issue here.
EDIT:
heres the test case code. Theres no errors in the test case code just in the program above only :
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include "iteratorG.h"
#include "positiveIntType.h"
#include "stringType.h"
#define MAXARRAY 5
/* Helper Functions Below */
/* Returns 1 if marks >= 50, 0 otherwise */
int passMarks(void *marks){
return (*((int *) marks) >= 50);
/* Easy to understand below ..
int *ip = (int *) marks;
if(*ip >= 50) { return 1; }
else { return 0; }
*/
}
/* Returns 1 if str starts with "jo" */
int prefixJo(void *str){
return (strncmp("jo", (char *) str, 2) == 0) ;
}
/* A function to print a string from a void pointer */
void prnStr(void *vp){
assert(vp != NULL);
printf(" %s", (char *) vp );
}
/* A function to print an integer from a void pointer */
void prnInt(void *vp){
assert(vp != NULL);
printf(" %d", *((int *) vp) );
}
/* Prints previous element using the given function 'fp'
examples: prnPrev(it1, prnInt); prnPrev(it2, prnStr);
*/
void prnPrev(IteratorG it, void (*fp) (void *p) ){
void *prevP = previous(it);
assert(prevP != NULL);
printf("> Previous value is: ");
fp(prevP);
printf("\n");
}
/* Prints next element using the given function 'fp'
examples: prnNext(it1, prnInt); prnNext(it2, prnStr);
*/
void prnNext(IteratorG it, void (*fp) (void *p) ){
void *nextP = next(it);
assert(nextP != NULL);
printf("> Next value is: ");
fp(nextP);
printf("\n");
}
/* Prints elements of 'it' from current to last position
using the given function 'fp'. The current position
of 'it' will change to the end of the list.
examples: prnIt(it1, prnInt); prnIt(it2, prnStr);
*/
void prnIt(IteratorG it, void (*fp) (void *p) ){
int count = 0;
while(hasNext(it)){
void *nextP = next(it);
count++;
if(count > 1) { printf(", "); }
fp(nextP);
}
printf("\n");
}
/* Few Tests Below */
void test1(){
printf("\n--==== Test-01 ====------\n");
IteratorG it1 = newIterator(positiveIntCompare, positiveIntNew, positiveIntFree);
int a[MAXARRAY] = { 25, 78, 6, 82 , 11};
for(int i=0; i<MAXARRAY; i++){
int result = add(it1 , &a[i]);
printf("> Inserting %d: %s \n", a[i], (result==1 ? "Success" : "Failed") );
}
freeIt(it1);
printf("--==== End of Test-01 ====------\n");
}
void test2(){
printf("\n--==== Test-02 ====------\n");
IteratorG it1 = newIterator(positiveIntCompare, positiveIntNew, positiveIntFree);
int a[MAXARRAY] = { 72, 14, 62, 8, 93};
for(int i=0; i<MAXARRAY; i++){
int result = add(it1 , &a[i]);
printf("> Inserting %d: %s \n", a[i], (result==1 ? "Success" : "Failed") );
}
prnNext(it1, prnInt);
prnNext(it1, prnInt);
prnPrev(it1, prnInt);
int newVal1 = 55;
int result1 = set(it1, &newVal1);
printf("> Set value: %d ; return val: %d \n", newVal1, result1 );
prnPrev(it1, prnInt);
freeIt(it1);
printf("--==== End of Test-02 ====------\n");
}
void test3(){
printf("\n--==== Test-03 ====------\n");
IteratorG it1 = newIterator(positiveIntCompare, positiveIntNew, positiveIntFree);
int a[MAXARRAY] = { 04, 54, 15, 12, 34};
for(int i=0; i<MAXARRAY; i++){
int result = add(it1 , &a[i]);
printf("> Inserting %d: %s \n", a[i], (result==1 ? "Success" : "Failed") );
}
reset(it1);
printf("> it1 (after reset): \n");
prnIt(it1, prnInt);
reset(it1);
IteratorG advIt1 = advance(it1, 4);
printf("> advance(it1, 4) returns: \n");
prnIt(advIt1, prnInt);
//IteratorG advIt2 = advance(it1, -3);
//printf("> advance(it1, -3) returns: \n");
//prnIt(advIt2, prnInt);
//printf("> In 'it1', ");
//prnPrev(it1, prnInt);
freeIt(it1);
//freeIt(advIt1);
//freeIt(advIt2);
printf("--==== End of Test-03 ====------\n");
}
int main(int argc, char *argv[])
{
test1();
test2();
test3();
return EXIT_SUCCESS;
}

Linked List program error? In C

Trying to study linked list and tried my program on gcc 4.1.2 on terminal and Xcode.
xcode Error: Thread 1: Exe_BAD_ACCESS(Code=1)
Terminal Error; Segmentation fault
and i have no clue what the xcode error is. for some reason it gives me that same error for some programs that work on other gcc?
Code :
#include <stdio.h>
#include <stdlib.h>
typedef struct node *link;
struct node {int item; link next;};
int main(int argc, const char * argv[]) {
int i;
link t = malloc(sizeof *t);
while ( t != NULL)
{
for ( i = 0; i < 10;i++)
{
t->item = i;
t = t->next;
}
}
int count = 0;
while ( t != NULL)
{
for ( i = 0; i < 10; i++)
{
if (count == 3)
{
printf("%d\n", t->item);
continue;
}
t = t->next;
count++;
}
}
}
You dereferenced t->next, which is allocated via malloc() and not assigned some value, and invoked undefined behavior. You have to allocate buffer for second node and later.
Also you should get the pointer t back before dealing with the list.
#include <stdio.h>
#include <stdlib.h>
typedef struct node *link;
struct node {int item; link next;};
int main(int argc, const char * argv[]) {
int i;
link t = malloc(sizeof *t);
link head = t; /* add this line to get the pointer back */
while ( t != NULL)
{
for ( i = 0; i < 10;i++)
{
t->item = i;
t->next = malloc(sizeof *t); /* add this line */
t = t->next;
}
}
int count = 0;
t = head; /* add this line to get the pointer back */
while ( t != NULL) /* convinated with inner loop, this will lead to infinite loop */
{
for ( i = 0; i < 10; i++) /* you may want to check if t != NULL here for safety */
{
/* not invalid but odd program that print the 4th element again and again */
if (count == 3)
{
printf("%d\n", t->item);
continue;
}
t = t->next;
count++;
}
}
}

Linked lists, operations with parameter

I'm trying to implement program in with i can create ~arbitrary number of singly linked lists dynamically and perform operations on particular one (defined by parameter). I create dynamic array of head pointers so that i can refer to the certain head node defined by paramater(index of an array + 1). Parameter is just (1,2,3..number of lists). So far I have managed to implement only initialise and push function but the program after complilation doesn't work as expected. Where is the problem?
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define CHUNK 10
typedef struct
{
char *str;
struct node *next;
} node;
node *initialise(node **array, int *amount_of_lists);
void push(node **array, int *amount_of_lists);
char *getString(void);
int main()
{
node **heads = NULL; //initially null, pointer to the dynamic array of head pointers
int amount_of_lists = 0;
int *no_of_heads = &amount_of_lists;
initialise(heads, no_of_heads);
initialise(heads, no_of_heads);
push(heads, no_of_heads);
push(heads, no_of_heads);
return 0;
}
node *initialise( node **array, int *amount_of_lists ) /*reallocate memory for another head pointer ans return the pointer to node*/
{
++(*amount_of_lists);
printf("\n%d", *amount_of_lists);
array = (node**)realloc(array, sizeof(node*)*(*amount_of_lists));
return array[(*amount_of_lists) - 1] = malloc(sizeof(node));
}
int readParameter(int *amount_of_lists)
{
int parameter = 0, control = 0;
bool repeat = 0;
do
{
if(repeat)
{
printf("\nWrong parameter, try again.");
}
printf("\n Enter list parameter: ");
control = scanf("%d", &parameter);
fflush(stdin);
repeat = 1;
}
while( control != 1 || parameter < 1 || parameter > (*amount_of_lists) );
return parameter;
}
void push(node **array, int *amount_of_lists)
{
int parameter = readParameter(amount_of_lists) - 1;
node *temp = array[parameter];
array[parameter] = malloc(sizeof(node));
array[parameter] -> next = temp;
array[parameter] -> str = getString();
}
char *getString(void)
{
char *line = NULL, *tmp = NULL;
size_t size = 0, index = 0;
int ch = EOF;
while (ch)
{
ch = getc(stdin);
/* Check if we need to stop. */
if (ch == EOF || ch == '\n')
ch = 0;
/* Check if we need to expand. */
if (size <= index)
{
size += CHUNK;
tmp = realloc(line, size);
if (!tmp)
{
free(line);
line = NULL;
break;
}
line = tmp;
}
/* Actually store the thing. */
line[index++] = ch;
}
return line;
}
As BLUEPIXY somewhat crypticly hinted at in his comment 1), in order to modify main()'s heads in initialise(), you have to pass heads by reference to initialise(), i. e. change
initialise(heads, no_of_heads);
initialise(heads, no_of_heads);
to
initialise(&heads, no_of_heads);
initialise(&heads, no_of_heads);
consequently
node *initialise( node **array, int *amount_of_lists )
changes to
node *initialise(node ***array, int *amount_of_lists)
and inside array changes to *array, i. e.
*array = realloc(*array, sizeof(node *) * *amount_of_lists);
return (*array)[*amount_of_lists - 1] = malloc(sizeof(node));

C Program: Create Linked List Using argv, argc, Segmentation Fault

I have a program that takes in strings using the command line prompts argv and argc. I keep getting a segmentation fault when I go to run the code and after much researching, I cannot determine what might be causing this. Maybe how I execute the code is the issue? I am using gcc -o code code.c then ./code one two three with one two three being the strings added to the linked list. Any assistance in determining where my error might be would be great.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
typedef struct list_node_s{
char the_char;
struct list_node_s *next_node;
}list_node;
void insert_node(list_node *the_head, char the_char);
void print_list(list_node *the_head);
int main(int argc, char *argv[]){
char next_char;
list_node *the_head = NULL;
insert_node(the_head, next_char);
the_head->next_node = malloc(sizeof(list_node));
if(the_head == NULL){
return 1;
}
the_head->the_char = 1;
the_head->next_node == NULL;
int the_count, the_count2;
for(the_count = 0; the_count < sizeof(argv); the_count++){
for(the_count2 = 0; argv[the_count][the_count2] != '\0'; the_count2++){
next_char = argv[the_count][the_count2];
insert_node(the_head, next_char);
}
}
print_list(the_head);
return (0);
}
void insert_node(list_node *the_head, char the_char){
list_node * current_node = the_head;
while (current_node->next_node != NULL) {
current_node = current_node->next_node;
}
current_node->next_node = malloc(sizeof(list_node));
current_node->next_node->the_char = the_char;
current_node->next_node->next_node = NULL;
}
void print_list(list_node *the_head){
if(the_head == NULL){
printf("\n");
}else{
printf("%c", the_head->the_char);
print_list(the_head->next_node);
}
}
Change this:
list_node *the_head = NULL;
insert_node(the_head, next_char);
the_head->next_node = malloc(sizeof(list_node));
to:
list_node the_head = { '\0', NULL };
to initialize the_head to an empty node.
One problem is in this function:
void insert_node(list_node *the_head, char the_char){
list_node * current_node = the_head;
while (current_node->next_node != NULL) {
current_node = current_node->next_node;
}
current_node->next_node = malloc(sizeof(list_node));
current_node->next_node->the_char = the_char;
current_node->next_node->next_node = NULL;
}
When you call it in main you're basically passing in NULL because you're setting the_head to NULL. You're trying to access current_node->next_node in the while loop conditions, but because of what you're passing in, you're basically doing NULL->next_node.
You need to initialize your head to an empty list_node. Basically since you're using a char as your node element you could set the value of the char to 0x00, which would make it a zero byte. Then that way you know that when you're at that value, you're at the head.
I don't mean to self-promote, but if you want to look at some code for this have a look at this github repo for the Barry_CS-331 Data Structures class. There's C and C++ in there for the Data Structures. I think it might have a list but if not you can use the stack and the queue as an overall example.
I have modified you code, there has some bugs:
1)、the key bug is in this code.
for(the_count = 0; the_count < sizeof(argv); the_count++)
{
for(the_count2 = 0; argv[the_count][the_count2] != '\0'; the_count2++)
{
next_char = argv[the_count][the_count2];
insert_node(the_head, next_char);
}
}
there some bugs:
you cann't use the_count < sizeof(argv), because of the type of argv is char* []; so sizeof(argv) maybe 4 or 8, based on your os.
the right is:
for(the_count = 1; the_count < argc; the_count++){
for(the_count2 = 0; argv[the_count][the_count2] != '\0'; the_count2++){
next_char = argv[the_count][the_count2];
insert_node(the_head, next_char);
}
}
2、this code aose has some bugs:
list_node *the_head = NULL;
insert_node(the_head, next_char);
the_head->next_node = malloc(sizeof(list_node));
if(the_head == NULL){
return 1;
}
the_head->the_char = 1;
the_head->next_node == NULL;
insert_node(the_head, next_char); is no need, you'd better do the_head->the_char = '\0', because of char 1 is no printable character.
One way:
#include <stdio.h>
#include <stdlib.h>
typedef struct list_node_s{
char the_char;
struct list_node_s *next_node;
}list_node;
void insert_node(list_node *the_head, char the_char);
void print_list(list_node *the_head);
int main(int argc, char *argv[]){
list_node *the_head = NULL;
int the_count, the_count2;
for(the_count = 0; the_count < argc; the_count++)
{
for(the_count2 = 0; the_count2 < strlen(argv[the_count]); the_count2++)
insert_node(&the_head, argv[the_count][the_count2]);
}
print_list(the_head);
return (0);
}
void insert_node(list_node **the_head, char the_char){
list_node *new_node;
list_node *tail_node;
/* Allocate and populate a new node. */
new_node = malloc(sizeof(list_node));
new_node->the_char = the_char;
new_node->next_node = NULL;
/* Is the_head already initialized? */
if(*the_head)
{
/* Yes... find the tail_node. */
tail_node = *the_head;
while(tail_node->next)
tail_node = tail_node->next;
/* Append the new_node to the end of the list. */
tail_node->next = new_node;
return;
}
/* the_head was not initialized. The new_node will be the head node. */
*the_head = new_node;
return;
}
void print_list(list_node *the_head){
if(the_head == NULL){
printf("\n");
}else{
printf("%c", the_head->the_char);
print_list(the_head->next_node);
}
}

Resources