Why I get this wrong output? - c

I created this simple double linked list.
The problem is that when I print all its elements, they have the same char value even if the variable "a" changes every time.
typedef struct node{
char *name;
struct node *n;
struct node *p;
} N;
N *h=NULL;//head
void insert(char *value){
N *temp=malloc(sizeof(N));
if(h==NULL){
h=temp;
temp->name=strdup(value);
}
else{
N *curr=h;
while(curr->n!=NULL)
curr=curr->n;
curr->n=temp;
temp->p=curr;
temp->name=strdup(value);
}
}
void print(){
N *temp=h;
printf("%s\n", temp->name);
while(temp->n!=NULL){
printf("%s\n", temp->name);
temp=temp->n;
}
}
int main(){
char a[...];
fgets(a,...)
//there is a while section: every time i enter in it, there is:
char *input=a;
insert(input);
print();
}
So I expected something as:
Lion
Bear
Goat
....
Instead i get:
Lion, then
Bear
Bear, then
Goat
Goat
Goat
etc...

There are a couple of issues. First you have a bug in print() that prevents the last value from being displayed. Check temp instead of temp->n:
void print()
{
N *temp=h;
while(temp !=NULL){
printf("%s\n", temp->name);
temp=temp->n;
}
}
Your extra printf() call (before the while loop) is why the first value was printed twice.
Also you must assign p and n when you add a new node. You can't assume that they will be NULL if you don't assign them.
void insert(char *value)
{
N *temp=malloc(sizeof(N));
if(h==NULL){
h=temp;
temp->p = NULL;
temp->n = NULL;
temp->name=strdup(value);
}
else{
N *curr=h;
while(curr->n!=NULL)
curr=curr->n;
curr->n=temp;
temp->p=curr;
temp->n = NULL;
temp->name=strdup(value);
}
}
Also, do you need the list to be double-linked? You never use the p pointer.

You're pointing to the same memory for each list element. This code
temp->name=value;
merely copies the value of the pointer to temp->name because of the definition of the structure:
typedef struct node{
char *name;
struct node *n;
struct node *p;
} N;
name is just a pointer. You need to duplicate the string that value points to, not just point name at value (input validation and error checking are left as an exercise for the reader...):
char *duplicateString( const char *inputString )
{
char newString = malloc( strlen( inputString ) + 1 );
strcpy( newString, inputString );
return( newString );
}
so
temp->name = duplicateString( value );
Just remember to call free( temp->name ) before you call free( temp ) to free your node.
or just use strdup() if you're on a POSIX system:
temp->name = strdup( value );

Related

Error in stack with linked list implementation

I'm trying to implement stack using linked list implementation. Its giving me "Segmentation Error". Please help me finding the error. This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 100
struct NODE {
char word;
struct NODE *next;
};
struct STACK {
struct NODE *head;
int size;
};
void pushStack(struct STACK *stack, char s);
void makeStack(struct STACK *stack, char *s);
void printStack(struct STACK *stack);
int main(){
char *s;
fgets(s,100,stdin);
struct STACK stack;
stack.head = NULL;
makeStack(&stack,s);
printStack(&stack);
return 0;
}
void pushStack(struct STACK *stack, char s){
struct NODE temp;
temp.word = s;
temp.next = stack->head;
stack->head = &temp;
}
void makeStack(struct STACK *stack, char *s){
char temp[MAX];
strcpy(temp,s);
for(int i=0; i<MAX; i++){
if(temp[i]=='\0') break;
pushStack(stack,temp[i]);
}
}
void printStack(struct STACK *stack){
struct NODE *trav = stack->head;
while (trav != NULL){
printf("%c", trav->word);
trav = trav->next;
}
}
MAX=100 is the limit I'm taking for string input. I haven't also added increasing the size because I'm just ignoring the increment of size for now. Before I could perfect the implementation
In main the s pointer is not initialized and it points nowhere.
int main(){
char *s; // <<< this is wrong, you want 'char s[100]' instead
fgets(s,100,stdin);
...
However the safest option is this:
int main(){
char s[100]; // declare array of 100 chars
fgets(s, sizeof(s), stdin); // sizeof(s) is the actual size of s (100 here)
...
This is wrong too: you store the pointer to the local variable temp, but that variables ceases to exist once you return from the pushStask function.
void pushStack(struct STACK* stack, char s) {
struct NODE temp;
temp.word = s;
temp.next = stack->head;
stack->head = &temp;
}
Instead you need to create a new struct NODE like this:
void pushStack(struct STACK* stack, char s) {
struct NODE* temp = malloc(sizeof *temp);
temp->word = s;
temp->next = stack->head;
stack->head = temp;
}
Instead of malloc(sizeof *temp) you could write sizeof(struct NODE), it's the same, but it's less fool proof because you could mistakenly write sizeof(struct STACK) which would compile fine, but the size of the allocated memory would be wrong.
Another problem: you don't assign the size field of the struct STACK, this is not a problem now, but it might become a problem later.
There are several drawbacks in your implementation of a stack.
The first one is that you are using a pointer with an indeterminate value to read a string
char *s;
fgets(s,100,stdin);
So the call of fgets invokes undefined behavior.
Moreover there is used a magic number 100.
You need to allocate a character array and use it to read a string.
#define MAX 100
//...
char s[MAX];
fgets( s, MAX, stdin );
Pay attention to that the name word for an object of the type char is confusing
struct NODE {
char word;
struct NODE *next;
};
You could define the structure like for example
struct NODE {
char c;
struct NODE *next;
};
or
struct NODE {
char item;
struct NODE *next;
};
Instead of separating the declaration and the initialization as you did
struct STACK stack;
stack.head = NULL;
forgetting to initialize the data member size (that by the way should have an unsigned integer type as for example size_t) you could just write for example
struct STACK stack = { NULL, 0 };
or
struct STACK stack = { .head = NULL, .size = 0 };
In the declaration of the function makeStack the second parameter should have the qualifier const because the passed string is not being changed within the function. And as a memory allocation in general can fail the function should report whether all characters of the string were pushed successfully. So the function declaration should look like
int makeStack( struct STACK *stack, const char *s );
It does not make a sense to declare a local array temp within the function
void makeStack(struct STACK *stack, char *s){
char temp[MAX];
//...
using the index variable i is redundant. Also the function fgets can append the new line character '\n' to the input string that you should not push on stack.
The function can be defined the following way
int makeStack( struct STACK *stack, const char *s )
{
int success = 1;
for ( ; *s && success; ++s )
{
if ( *s != '\n' )
{
success = pushStack( stack, *s );
}
}
return success;
}
Another approach is to remove the new line character from the input string before passing it to the function makeStack.
For example
s[ strcspn( s, "\n" ) ] = '\0';
makeStack( &stack, s );
If it is the user that is responsible whether to push the new line character on stack or not then the function makeStack can be simplified
int makeStack( struct STACK *stack, const char *s )
{
int success = 1;
for ( ; *s && success; ++s )
{
success = pushStack( stack, *s );
}
return success;
}
Correspondingly the function pushStack also should be redefined.
For starters it shall dynamically allocate a new node. Otherwise you will try to add nodes that are local to the function and will not be alive after exiting the function that again results in undefined behavior.
The function pushStack can be defined the following way.
int pushStack( struct STACK *stack, char c )
{
struct NODE *temp = malloc( sizeof( struct NODE ) );
int success = temp != NULL;
if ( success )
{
temp->word = c;
temp->next = stack->head;
stack->head = temp;
++stack->size;
}
return success;
}
The parameter of the function printStack should have the qualifier const because the stack itself within the function is not being changed.
The function can be defined at least the following way
void printStack( const struct STACK *stack )
{
for ( const struct NODE *trav = stack->head; trav != NULL; trav = trav->next )
{
printf( "%c", trav->word );
}
}

Inserting string into stack returns random character

Working on pushing a string onto my stack and currently I am getting random characters ( the characters are not getting pushed on the stack because when I check afterwards my stack is empty)
here are the relevant functions and structure
typedef char stackitem;
struct stack {
stackitem d;
struct stack *next;
};
typedef struct stack ELEMENT;
typedef ELEMENT *POINTER;
void push(POINTER *Top, stackitem a)
/* Put item a into the top of the stack */
{
POINTER temp;
temp = malloc(sizeof(ELEMENT));
temp->d = a;
temp->next = *Top;
*Top = temp;
printf("Insert element %c\n", temp->d);
}
void push_string(POINTER *Top,char *string)
/* Push a string of characters into a stack. */
{
char *tmp = malloc(strlen(string) + 1);
if (tmp)
strcpy(tmp, string);
push(&Top,tmp);
Parts of the second function I found on another SO thread.
And this is how I am using it:
main()
{
POINTER top;
top= (POINTER) NULL;
stackitem A='A';
stackitem B='B';
char *C="12345";
push_string(&top,C);
print_stack(top);
return 0;
}
How am i able to add a string to the stack? the push function works for pushing chars onto the stack but I cant get it to push a whole string.
Firstly, turn on all warning (options -Wall -pedantic).
The compiler will likely complain about the casting between non-compatible types.
The function push() is dedicated to put a single char on the stack, whereas push_string() is dedicated to put all characters of string one by one.
Therefore to put a string you should put each character of the string individually.
void push_string(POINTER *Top,char *string) {
for (char *s = string; *s; ++s)
push(Top, *s);
}
The code snippet of the function push_string as is does not make a sense.
For example there is no any need to create a copy of the passed string.
char *tmp = malloc(strlen(string) + 1);
if (tmp)
strcpy(tmp, string);
Secondly this call
push(&Top,tmp);
has invalid types of arguments.
The function push_string can look the following way
void push_string( POINTER *Top, const char *string )
{
for ( ; *string; ++string ) push( Top, *string );
}
Here is a demonstrative program.
#include <stdio.h>
#include <stdlib.h>
typedef char stackitem;
struct stack {
stackitem d;
struct stack *next;
};
typedef struct stack ELEMENT;
typedef ELEMENT *POINTER;
int push( POINTER *Top, stackitem c )
{
POINTER temp = malloc( sizeof( ELEMENT ) );
int success = temp != NULL;
if ( success )
{
temp->d = c;
temp->next = *Top;
*Top = temp;
}
return success;
}
void push_string( POINTER *Top, const char *string )
{
for ( ; *string; ++string ) push( Top, *string );
}
int pop( POINTER *Top, stackitem *c )
{
int success = *Top != NULL;
if ( success )
{
*c = ( *Top )->d;
POINTER temp = *Top;
*Top = ( *Top )->next;
free( temp );
}
return success;
}
int main(void)
{
POINTER top = NULL;
push_string( &top, "12345" );
for ( char c; pop( &top, &c ); )
{
putchar( c );
}
putchar( '\n' );
return 0;
}
The program output is
54321
Pay attention to that you should check that the memory allocation for a new node of the stack was successful.
In the demonstrative program the function push reports whether pushing an element was successful.
The function push_string also should report whether a string was pushed successfully. In this case it can be defined the following way
int push_string( POINTER *Top, const char *string )
{
while ( *string && push( Top, *string ) ) ++string;
return *string == '\0';
}
Just substitute the function push_string in the demonstrative program above with this one and the program will work as expected.

Linked list of chars in C

I'm trying to create a linked list holding char type data.
For some reason, the code does not work. The GCC compiler's warning for function "add_bottom_ListEl" is
"warning: passing argument 2 of 'add_bottom_listEl' makes integer from pointer without a cast"
and
"note: expected 'char' but argument is of type 'char * "
I suspect that there's something wrong about the way I use pointers, but I've tried many, many combinations, passing pointers to the function etc... But nothing seemed to work.
Here's main function and all the others used. MAX_CHAR is defined in all files (#define MAX_CHAR 30)
int main()
{
char name[MAX_CHAR];
scanf("%s", name);
ListEl *head = malloc(sizeof(ListEl));
strcpy(head->name, name);
head->next = NULL;
printf("%s", head->name);
add_bottom_listEl(head, name);
print_listEl(head);
return 0;
}
void add_bottom_listEl (ListEl *head, char name)
{
ListEl *newEl;
while(head->next!=NULL)
{
head=head->next;
}
newEl = (ListEl*) malloc(sizeof(ListEl));
strcpy(newEl->name, name);
newEl->next = NULL;
}
void print_listEl(ListEl* head)
{
puts("print");
ListEl* current = head;
while (current!=NULL)
{
int i=1;
printf("%d.%s\n", i, current->name);
++i;
current = current -> next;
}
}
The ListEl structure is just a regular element of a linked list
struct ListEl
{
char name[MAX_CHAR];
struct ListEl* next;
};
Obviously, I used
typedef struct ListEl ListEl;
Every linked list tutorial on the internet or this site is only showing how to handle lists with integers or numbers in general, but not arrays (chars). Can anyone help me out here?
Your function "add_bottom_listEl" takes one character called "name", not a character array (or a pointer to a character). My guess is you want it to be:
add_bottom_listEl(ListEl *head, char *name)
If your intention in add_bottom_listEl is to modify and pass back head, then head has to be passed as a pointer to a pointer:
void add_bottom_listEl(ListEl** head, char* name) {
if ( head == NULL ) {
//head is invalid, do nothing
return;
}
//Use calloc instead of malloc to initialise the memory area
ListEl* newEl = (ListEl*)calloc(1, sizeof(ListEl));
//Ensure only name of the permissible length is copied
strncpy(newEl->name, name, MAX_CHAR-1);
//No need to do this now...calloc will initialise it to NULL
//newEl->next = NULL;
if ( *head == NULL ) {
//No nodes in list yet, this is the first
*head = newEl;
} else if ( *head != NULL ) {
//Find the end of the list
while((*head)->next!=NULL) {
*head = (*head)->next;
}
}
//Add the new node to the list
*head = newel;
}
When you call this modified version of the function pass the address of the pointer:
add_bottom_listEl(&head, name);
You can make your typedef more readable by doing this:
typedef struct _listEl {
char name[MAX_CHAR];
struct _listEl* next;
} ListEl;
The line
void add_bottom_listEl (ListEl *head, char name)
should be
void add_bottom_listEl (ListEl *head, char* name)

Cannot get input from user to work in place of manual strings entered in code

I am trying to get a program to run that basically takes an input string and sends it through some code and sorts it using linked lists alphabetically. I have figured out how to make this work using manual (in the actual code) text input, but I cannot get it to work when I am trying to take input from the user.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct llist {
char *value;
struct llist *next;
};
int compare (struct llist *one , struct llist *two)
{
return strcmp(one->value, two->value);
}
void add(struct llist **pp, char *value, int (*cmp)(struct llist *l, struct llist *r)) {
struct llist *new;
new = malloc(sizeof(*new));
new->value = value;
for ( ; *pp != NULL; pp = &(*pp)->next) {
if (cmp(*pp, new) > 0 ) break;
}
new->next = *pp;
*pp = new;
}
void display(struct llist *ptr) {
for (; ptr != NULL; ptr = ptr->next) {
printf("%s\n", ptr->value);
}
}
int main(void) {
struct llist *root = NULL;
char string;
printf("Please enter a string to be sorted alphabetically and displayed with a character count: ");
string = getchar();
while (string != 10){
add(&root,&string, compare);
string = getchar();
}
display(root);
return 0;
}
looking in the main function I'm quite certain it has something to do with getchar and the fact that it reads characters in as ints, but I can't figure out how to fix this, the output is just a bunch of empty lines. but when the while loop is removed and the strings are entered like below in main, it works fine? why is this so?
int main(void) {
struct llist *root = NULL;
char string;
printf("Please enter a string to be sorted alphabetically and displayed with a character count: ");
add(&root,"t", compare);
add(&root,"h", compare);
add(&root,"i", compare);
add(&root,"s", compare);
add(&root,"m", compare);
add(&root,"y", compare);
add(&root,"t", compare);
add(&root,"e", compare);
add(&root,"x", compare);
add(&root,"t", compare);
display(root);
return 0;
}
the output is now
e
h
i
m
s
t
t
t
x
y
which is correct,
Can anyone help me?
When you write "t" in the example, you get the address of an array. That address is different for each value you pass to add. However, the address of string does not change, and you are setting new->value to the same thing each time you call add. Instead of new->value = value, try new->value = *value (and all of the associated changes necessary).
There are not too many changes needed. Note that terminating after a single string of input is not very nice behavior. A good exercise would be to write a destructor that tears down the string after the first line and then sorts the next. Another nice exercise would be to sort arguments if any are passed, reading stdin if no arguments are given.
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct llist {
char value; /* CHANGE */
struct llist *next;
};
typedef int (*compar)( struct llist *one , struct llist *two );
int
compare( struct llist *one , struct llist *two )
{
return tolower( one->value ) > tolower( two->value ); /* CHANGE */
}
void *
xmalloc( size_t s )
{
void *v = malloc( s );
if( v == NULL ) {
perror( "malloc" );
exit( EXIT_FAILURE );
}
return v;
}
void
add( struct llist **pp, char value, compar cmp ) /* CHANGE */
{
struct llist *new;
new = xmalloc( sizeof *new ); /* Check for errors */
new->value = value; /* CHANGE the type of value above */
for( ; *pp != NULL; pp = &(*pp)->next ) {
if( cmp( *pp, new ) > 0 )
break;
}
new->next = *pp;
*pp = new;
}
void
display( struct llist *ptr )
{
for( ; ptr != NULL; ptr = ptr->next ) {
putchar( ptr->value ); /* CHANGE */
}
putchar( '\n' );
}
int
main( void )
{
struct llist *root = NULL;
char string;
while( (string = getchar()) != '\n' ) { /* Optional CHANGE (1) */
add( &root,string, compare );
}
display(root);
return 0;
}
/*
* (1) Using "'\n'" instead of 10 is necessary for readability,
* portability, and sanity of future maintainers.
*
* Writing getchar() only once is cleaner.
*/
With your hard coded entry code you are passing in string's to add while in your user input code you are only passing in a pointer to a single character. A char* is not necessarily a string in C, it may point to a string, but it doesn't have to.
In C a string is a buffer of characters that ends with a null zero, the character '\0' (which is usually just the value 0). When you are using getchar your are passing a pointer to a character - and that character does not have a null zero after it, so it is not a valid C string.
If you want to keep your code using getchar you need to use a buffer that will store a null zero after that character. You can do that will a small array as below:
int main(void) {
struct llist *root = NULL;
char string[2];
string[1] = '\0'; // Ensure that we have a null terminated string
printf("Please enter a string to be sorted alphabetically and displayed with a character count: ");
string[0] = getchar();
while (string != '\n'){
add(&root,string, compare);
string[0] = getchar();
}
display(root);
return 0;
}
Cleaned-up a few things
1) As #shf301 siad, need to pass a string, not just a pointer to a single char.
2) Need to create copies of the string - notice strdup.
3) While loop should break on '\n and EO and maybe '\0. getchar() returns an int for a reason: EOF and 0 to UCHAR_MAX (e. g. 255).
4) Should free() resources at the end - not shown.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
// In case you library does not have strdup() ...
char *strdup(const char *s) {
if (s == NULL) return NULL;
size_t siz = strlen(s) + 1;
char *y = malloc(siz);
if (y != NULL) {
memcpy(y, s, siz);
}
return y;
}
struct llist {
char *value;
struct llist *next;
};
int compare(struct llist *one, struct llist *two) {
return strcmp(one->value, two->value);
}
void add(struct llist **pp, char *value,
int(*cmp)(struct llist *l, struct llist *r)) {
struct llist *new;
new = malloc(sizeof(*new));
new->value = strdup(value);
for (; *pp != NULL; pp = &(*pp)->next) {
if (cmp(*pp, new) > 0)
break;
}
new->next = *pp;
*pp = new;
}
void display(const struct llist *ptr) {
for (; ptr != NULL; ptr = ptr->next) {
printf("%s\n", ptr->value);
}
}
int main(void) {
struct llist *root = NULL;
char string[2];
string[1] = '\0';
printf("Please enter a string to be sorted alphabetically"
" and displayed with a character count: ");
int ch;
while ((ch = getchar()) != EOF && ch != '\n' && ch != '\0') {
string[0] = ch;
add(&root, string, compare);
}
display(root);
return 0;
}

Structure Link List Segmentation-Fault

I just got started on a lab of mine where I calculate the GPA of courses whose information is stored in a linked list of structures. As of now, I'm attempting to just print out all the course information to ensure that they have been properly initialized and added to the link list.
I'm running into a problem though because I keep getting a Segmentation Fault. I understand what the Segmentation Fault means, but I do not know where I am making my mistake. Any help would be appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#define MAX_CLASSES 20
/* Function Prototypes */
struct course * initcourse( int, char *, char *, float, char *, char *);
void add( struct course * );
/* Definition of a data node holding course information */
struct course {
int term;
char name[15];
char abbrev[20];
float hours;
char grade [4];
char type[12];
struct course *next;
};
/* head points to first node in list, end points to last node in list */
/* initializes both to NULL, no nodes yet */
struct course *head = (struct course *) NULL;
struct course *end = (struct course *) NULL;
/* Initializes a node, allocates memory for the node, and returns */
/* a pointer to the new node. Must pass correct parameters. */
struct course * initcourse( int term, char *name, char *abbrev, float hours, char *grade, char *type)
{
struct course *ptr;
ptr = (struct course *) calloc( 1, sizeof(struct course ) );
if( ptr == NULL )
return (struct course *) NULL;
else
{
ptr->term = term;
strcpy( ptr->name, name );
strcpy( ptr->abbrev, abbrev );
ptr->hours = hours;
strcpy( ptr->grade, grade );
strcpy( ptr->type, type );
return ptr;
}
}
/* This adds a node to the end of the list. You must allocate a node and */
/* then pass its address to this function */
void add(struct course *new)
{
if (head == NULL)
{
head = new;
}
else
{
end->next = new;
end = new;
}
}
/* Prints all information in a node */
void printnode( struct course *ptr )
{
printf("Term ->%d\n", ptr->term );
printf("Name ->%s\n", ptr->name );
printf("Abbreviation ->%s\n", ptr->abbrev );
printf("Hours ->%f\n", ptr->hours );
printf("Grade ->%s\n", ptr->grade );
printf("Type ->%s\n", ptr->type );
}
/* Prints List of Nodes */
void printlist( struct course *ptr )
{
while( ptr != NULL )
{
printnode( ptr );
ptr = ptr->next;
}
}
/* Calculates GPA */
/* float gpa ( struct course *ptr ) */
/* { */
/* float totalhours; */
/* float gpa; */
/* float gradepoints; */
/* while (ptr != NULL ) */
/* { */
/* totalhours += (ptr->hours); */
/* gradepoints = (ptr->hours * ptr->grade); */
/* } */
/* gpa = (gradepoints /ptr->hours); */
/* } */
int main()
{
int term;
char name[15];
char abbrev[20];
float hours;
char grade[4];
char type[12];
float gpa;
struct course *ptr;
struct course course1, course2, course3;
course1.term = 1234;
strcpy(course1.name,"cse1234");
strcpy(course1.abbrev,"systems");
course1.hours = 4;
strcpy(course1.grade,"A");
strcpy(course1.type,"GEC");
ptr = initcourse(course1.term, course1.name, course1.abbrev, course1.hours, course1.grade, course1.type);
struct course *head, *ptr2;
head = ptr;
// ptr2 = ptr;
add(ptr);
course2.term = 4332;
strcpy(course2.name,"cse4332");
strcpy(course2.abbrev,"Database");
course2.hours = 4;
strcpy(course2.grade,"B");
strcpy(course2.type,"Technical");
ptr2 = initcourse(course2.term, course2.name, course2.abbrev, course2.hours, course2.grade, course2.type);
add(ptr2);
printlist(head);
}
void add(struct course *new)
{
if (head == NULL)
{
head = new;
}
else
{
end->next = new;
end = new;
}
}
You need to set end to new when inserting the first node (when head == NULL), otherwise you're dereferencing a null-pointer when adding further nodes.
And in initcourse, you ought to set the next member to NULL, since it is not guaranteed by the standard that all-bits-0 is a null-pointer representation (it very likely is, but there's no guarantee).
Also,
struct course *head, *ptr2;
head = ptr;
declares a new local variable head that shadows the global one, and instead of assigning directly to head (even though it's the wrong one), you should call add(ptr);.
You dont initialize the next pointer, so the last element contains a bad pointer, pointing to some garbage.
You also don't initialize end.
Another problem (not related to the crash) is that this code will create a duplicate entry:
head = ptr;
add(ptr);
There're other problems. You really should get a debugger and see what's going on.

Resources