I'm just learning linked lists, and want to make one with inputs from the console, but somehow it's not working.
#include <stdio.h>
#include <stdlib.h>
typedef struct datatype Node;
struct datatype {
int data;
Node *next;
};
int main() {
int i,n;
Node *node[50];
printf("Number of intergers: ");
scanf("%d",&n);
for(i=0; i<n; i++) {
printf("Enter interger one by one: ");
scanf("%d",&node[i]->data);
node[i]->next=node[i+1];
}
for(i=0;i<n;i++)
printf("%d->",node[i]->data);
}
Building on Andreas's comment, here is a commented and memory safe implementation. You don't necessarily have to use malloc and free; you could instead have a fixed memory pool:
#define MAX_NODE_SIZE 256
...
Node node[MAX_NODE_SIZE];
followed by a check to make sure the user never puts n greater than MAX_NODE_SIZE. However if you tried to implement list inserts and deletes things would get complicated. Also, using an index "i" to iterate through a linked list kind of defeats the point of having a linked list.
Here is the malloc/free version:
#include <stdio.h>
#include <stdlib.h>
typedef struct datatype Node;
struct datatype {
int data;
Node *next;
};
int main() {
//Allocate the root node
Node *rootnode=malloc(sizeof(Node));
rootnode->data=0; rootnode->next=NULL;
Node *currentnode=rootnode;
//Populate n and check for validity
printf("Number of integers: ");
int n;
scanf("%d",&n);
if(n<=0){
printf("List must have a nonzero/nonnegative number of elements.\n");
return 1;
}
//Populate the list
for(int i=0; i<n; i++) {
printf("Enter integer one by one: ");
scanf("%d",¤tnode->data);
//If there is more data...
if(i!=n-1){
//Allocate room for the data
currentnode->next=malloc(sizeof(Node));
//Initialize things correctly
currentnode->next->data=0;
currentnode->next->next=NULL;
//Step to the next node.
currentnode=currentnode->next;
}
}
//Print the list
currentnode=rootnode;
do {
printf("%d",currentnode->data);
if(currentnode->next!=NULL)
printf(" -> ");
else
printf("\n");
} while((currentnode=currentnode->next)!=NULL);
//Deallocate the list
currentnode=rootnode;
while(currentnode!=NULL){
Node *next=currentnode->next;
free(currentnode);
currentnode=next;
}
return 0;
}
Example output:
user#desktop:~$ ./a.out
Number of integers: 3
Enter integer one by one: 1
Enter integer one by one: 2
Enter integer one by one: 3
1 -> 2 -> 3
You must allocate memory for the individual nodes of the linked list. Instead, you are allocating memory for 50 pointers to individual nodes, but not for the nodes themselves.
I suggest you create a standard linked list and use the function malloc for the individual nodes, like this:
typedef struct Node {
int data;
struct Node *next;
} Node;
int main( void )
{
//this pointer always points to the first element, or NULL if there is no first element
Node *pRoot = NULL;
//this pointer always points to the NULL pointer at the end of the list, which is, when the list is empty, the root pointer
Node **ppNext = &pRoot;
Node *pCurrent;
int retval, n;
//ask user for total number of data elements
printf( "Number of integers: " );
retval = scanf( "%d", &n );
if ( retval != 1)
{
fprintf( stderr, "scanf failed!\n" );
goto cleanup;
}
//build the list from user input
for ( int i = 0; i < n; i++ )
{
//allocate memory for new node
pCurrent = malloc( sizeof( Node ) );
if ( pCurrent == NULL )
{
fprintf( stderr, "malloc failed!\n" );
goto cleanup;
}
//ask user for individual data elements
printf( "Enter integer one by one: " );
retval = scanf( "%d", &pCurrent->data );
if ( retval != 1 )
{
fprintf( stderr, "scanf failed!\n" );
free( pCurrent );
goto cleanup;
}
pCurrent->next = NULL;
//link new node to linked list and update ppNext
*ppNext = pCurrent;
ppNext = &pCurrent->next;
}
//print the list
for ( pCurrent = pRoot; pCurrent != NULL; pCurrent = pCurrent->next )
{
printf( "%d\n", pCurrent->data );
}
cleanup:
//free the linked list
for ( pCurrent = pRoot; pCurrent != NULL; )
{
Node *tmp = pCurrent;
pCurrent = pCurrent->next;
free( tmp );
}
return 0;
}
Please note that in my code, before I use the value written to by scanf, I check the return value of scanf. This is necessary because the function may fail and not write any value, for example when the user enters letters instead of numbers. See this page for further information:
A beginner's guide away from scanf()
Related
My goal is to analyze a text file, tokenize each word, then alphabetize each word with its word frequency.
Example:
Input: The house is on the ground on earth.
Output:
earth - 1
ground - 1
house - 1
is - 1
on - 2
the - 2
I have been able to open the file, read the file line by line, tokenize each word, converted the tokens to lowercase. I am stuck grouping and alphabetizing each token.
#include <stdio.h>
#include <stdlib.h>
void lower_string(char s[]);
int main()
{
FILE *file;
//char path[100];
char ch[100];
int characters;
/* Input path of files to merge to third file
printf("Enter source file path: ");
scanf("%s", path);
file = fopen(path, "r");*/
file = fopen("test.txt", "r"); //testing w.o repeated input
/* Check if file opened successfully */
if (file == NULL)
{
printf("\nUnable to open file.\n");
printf("Please check if file exists and you have read privilege.\n");
exit(EXIT_FAILURE);
}
const char delim[] = " ,.;!?[\n]";
char *token;
int tokenNum;
while (fgets(ch, sizeof(ch), file) != NULL)
{
lower_string(ch);
token = strtok(ch, delim);
while (token != NULL)
{
printf("Token:%s\n", token);
token = strtok(NULL, delim);
tokenNum++;
}
}
printf("%d\n", tokenNum); //total words testing
/* Close files to release resources */
fclose(file);
return 0;
}
void lower_string(char s[])
{
int c = 0;
while (s[c] != '\0')
{
if (s[c] >= 'A' && s[c] <= 'Z')
{
s[c] = s[c] + 32;
}
c++;
}
}
I have been looking into building and manipulating an ordered linked list of integers and binary search tree of integers. I'm having a hard time figuring out where I should begin to implement these features. So far i have been looking at the code below for ordered linked list.
#include <stdio.h>
#include <stdlib.h>
//These structures are declared globally so they are available to all functions
//in the program.
typedef struct list_node_s
{ //defines structure of one node
int key; //key value - here an integer
int count; //frequency key value encountered in input
struct list_node_s *restp; //pointer to the next node in list = NULL if EOL
} list_node_t;
typedef struct //defines head of list structure
{
list_node_t *headp; //pointer to first node in list, NULL if list is empty
int size; //current number of nodes in the list
} ordered_list_t;
//Prototypes
list_node_t * insert_in_order (list_node_t * old_listp, int new_key);
void insert (ordered_list_t * listp, int key);
int delete (ordered_list_t * listp, int target);
list_node_t * delete_ordered_node (list_node_t * listp, int target,int *is_deleted);
void print_list (ordered_list_t * listp);
#define SEND -999 //end of input sentinal
int main (void)
{
int next_key;
ordered_list_t my_list = {NULL, 0};
printf("\n\nProgram to build, display and manipulate (delete) an Ordered Linked List \n");
printf("\nAdapted from code in \"Problem Solving and Programming in C\" by J.R. Hanly and E.B. Koffman\n\n");
printf ("enter integer keys - end list with %d\n", SEND);
/* build list by in-order insertions*/
for (scanf ("%d", &next_key);
next_key != SEND;
scanf ("%d", &next_key))
{
insert (&my_list, next_key);
}
/* Display completed list */
printf ("\nOrdered list as built:\n");
print_list(&my_list);
/* Process requested deletions */
printf("enter key value for node to be removed from list or %d to end > ", SEND);
for (scanf ("%d", &next_key);
next_key != SEND;
scanf ("%d", &next_key))
{
if (delete (&my_list, next_key))
{
printf ("%d deleted.\n New list:\n", next_key);
print_list (&my_list);
}
else
{
printf ("No deletion. %d not found\n", next_key);
}
printf ("enter key value for node to be removed from list or %d to end > ", SEND);
}
return (0);
}
/* prints contents of a linked list Display the elements in the list pointed to by the pointer list.*/
void print_list (ordered_list_t * listp)
{
list_node_t * tmp;
for (tmp = listp->headp; tmp != NULL; tmp = tmp->restp)
printf ("key = %d; count = %d\n", tmp->key, tmp->count);
printf ("\n\n");
}
//Inserts a new node containing new_key into an existing list and returns a pointer to the first node of the new list
list_node_t * insert_in_order (list_node_t * old_listp, int new_key)
{
list_node_t * new_listp;
if (old_listp == NULL) //check for end of list (EOL)
{
new_listp = (list_node_t *) malloc (sizeof (list_node_t));
new_listp->key = new_key;
new_listp->count = 1;
new_listp->restp = NULL;
}
else if (old_listp->key == new_key) //check for matching key, increment count
{
old_listp->count++;
new_listp = old_listp;
}
else if (old_listp->key > new_key) //Next node key value > new key, so insert new node at current location
{
new_listp = (list_node_t *) malloc (sizeof (list_node_t));
new_listp->key = new_key;
new_listp->count = 1;
new_listp->restp = old_listp;
}
else
{
new_listp = old_listp;
new_listp->restp = insert_in_order (old_listp->restp, new_key);
}
return (new_listp);
}
//inserts a node into an ordered list_node_t
void insert (ordered_list_t * listp, int key)
{
++(listp->size);
listp->headp = insert_in_order (listp->headp, key);
}
//deletes the first node containing the target key from an ordered list; returns 1
//if target found & deleted, 0 otherwise (means target not in list)
int delete (ordered_list_t * listp, int target)
{
int is_deleted;
listp->headp = delete_ordered_node (listp->headp, target, &is_deleted);
if (is_deleted)
--(listp->size); //reduce current node count (size); keep size of list current
return (is_deleted);
}
/* deletes node containing target key from a list whose head is listp; returns a pointer
to the modified list (incase it is the first node, pointed to by listp), frees
the memory used by tyhe deleted node and sets a flag to indicate success (1) or
failure (0; usually means no such node found).
*/
list_node_t * delete_ordered_node (list_node_t * listp, int target, int *is_deleted)
{
list_node_t *to_freep, *ansp;
// if list empty, nothing to do; return NULL
printf ("check for empty list; target: %d \n", target);
if (listp == NULL)
{
*is_deleted = 0;
ansp = NULL;
}
//if first node is to be deleted, do it; relink rest of list to list header struct
else if (listp->key == target)
{
printf ("at first node; target: %d \n", target);
*is_deleted = 1;
to_freep = listp; //keeps track of node memory location to be freed
ansp = listp->restp;
free (to_freep); //release the memory of the deleted node for reuse
}
//if target exists, it is further down the list (recursive step), make recursive call
//to move down the list looking for the target value
else
{
printf ("chase down list to find: %d \n", target);
ansp = listp;
ansp->restp = delete_ordered_node (listp->restp, target, is_deleted);
}
return (ansp);
}
I'm finding it hard to implement that with strtok.
12/4 EDIT:
added: Nodes for BST.
Questions-
Don't know if key needs to be tracked.(I assume it'll be useful to pull specific words).
Where/how would I add the logic to alphabetize the tree.(study sources appreciated)
How do I pass each word through this tree?
#define WLENGTH 100
//Base Node info
struct node
{
char word[WLENGTH];
int key;
int freq;
struct node *left, *right;
};
//Function to create a new node
struct node *newNode(char wordn, int item, int freqn)
{
struct node *temp = (struct node *) malloc(sizeof(struct node));
temp->word = wordn;
temp->key = item;
temp->freq = freqn;
temp->left = temp->right = NULL;
return temp;
}
//Function to place nodes in order
void inorder(struct node *root)
{
if (root != NULL)
{
inorder(root->left);
printf("%d ", root->key);
inorder(root->right);
}
}
/*Function to insert a new node with given key*/
struct node* insert(struct node* node, int key)
{
/* If the tree is empty, return a new node */
if (node == NULL)
return newNode(key);
/* Otherwise, recur down the tree */
if (key < node->key)
node->left = insert(node->left, key);
else if (key > node->key)
node->right = insert(node->right, key);
/* return the (unchanged) node pointer */
return node;
}
At the request of the OP, here is a bit of code to bulk load an entire text file for processing:
FILE *mustOpen( char *fname, char *mode ) {
FILE *fp = fopen( fname, mode );
if( fp == NULL ) {
fprintf( stderr, "Cannot open '%s'\n", fname );
exit( EXIT_FAILURE );
}
return fp;
}
// Passed the path to a file, opens, measures and bulk loads entire file (plus terminating '\0')
char *loadFile( char *fname ) {
FILE *fp = mustOpen( fname, "rb" );
fseek( fp, 0, SEEK_END );
size_t size = ftell( fp );
fseek( fp, 0, SEEK_SET );
char *buf;
if( ( buf = malloc( size + 1) ) == NULL )
fprintf( stderr, "Malloc() failed\n" ), exit( EXIT_FAILURE );
if( fread( buf, sizeof *buf, size, fp ) != size )
fprintf( stderr, "Read incomplete\n" ), exit( EXIT_FAILURE );
fclose( fp );
*(buf + size) = '\0'; // xtra byte allows strXXX() to work
return buf; // pointer to heap allocated buffer containing file's bytes
}
Remember to free() the buffer when done with its contents.
With the entire text loaded (and NULL terminated), here is a way to skip along the entire "string" finding each "word" (as defined by the delimiters):
for( char *cp = buf; (cp = strtok( cp, delim )) != NULL; cp = NULL ) {
/* process each single "word" */
}
Since the "text" is in memory, instances of each of the "words" are in memory, too. All that's needed is populating a BST with nodes that 'point to' one instance of each "word" and a counter that counts multiple occurrences of each word.
Finally, an "in order" traversal of the BST will give an alphabetised list of words and their frequency in the text.
Be sure to compartmentalize each of the functions. The "blocks" of functionality can then be re-used in other projects, and, who knows?... You may want to first load a dictionary and only report the words (and locations) that do not appear in the dictionary (typos?). The code that handles the BST "structure" (searching, adding, traversing) should be somewhat independent of what "information fields" comprise each node.
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
struct node {
int data;
struct node* nextptr;
} * manode;
void add();
void delete ();
void display();
int main()
{
int choice;
int echoice;
while (choice != 4) {
printf("\n \t ENTER YOUR CHOICE FOR SINGLE LINKED LIST ");
printf("\n \t 1. ADD ELEMENT ");
printf("\n \t 2. DISPLAY ELEMENT ");
printf("\n \t 3. DELETE ELEMENT ");
printf("\n \t 4. EXIT ");
scanf("%d", &choice);
switch (choice) {
case 1:
while (echoice != 0) {
add();
printf("\n DO YOU WANT TO CONTINUE 1/0 ");
scanf("%d", &echoice);
}
break;
case 2:
display();
break;
case 3:
delete ();
break;
case 4:
exit(0);
break;
default:
printf("\n \t WRONG VALUE ENTERED ");
};
}
return 0;
}
#Add function is responsible to add the first node and all the remaining nodes as well.
void add()
{
struct node *tmp, *tmp2;
tmp = malloc(sizeof(struct node));
tmp2 = malloc(sizeof(struct node));
int value;
printf(" ENTER THE VALUE YOU WANT TO ENTER ");
scanf("%d", &value);
if (manode == NULL) {
manode = malloc(sizeof(struct node));
printf(" FIRST ENTRY ");
manode->data = value;
manode->nextptr = NULL;
tmp = manode;
printf("THE DATA %d ", manode->data);
}
else {
if (tmp2 == NULL) {
printf("\n MEMORY ALLOCATION FAILED");
}
else {
tmp2->data = value;
tmp2->nextptr = NULL;
tmp->nextptr = tmp2;
tmp = tmp->nextptr;
}
}
//manode=tmp;
}
void display()
{
struct node* tmp1;
if (manode == NULL) {
printf(" MEMORY ALLOCATION FAILED ");
}
else {
tmp1 = manode;
while (tmp1 != NULL) {
printf("\n%d DATA IS DISPLAY \n", tmp1->data);
tmp1 = tmp1->nextptr;
}
}
}
void delete ()
{
struct node* tmp;
if (manode == NULL) {
printf("NOTHING TO DELETE ");
}
else {
tmp = malloc(sizeof(struct node));
}
}
Kindly copy and compile the code, it's working but it doesn't display the contents in the list. Kindly copy and compile the code, it's working but it doesn't display the contents in the list.Kindly copy and compile the code, it's working but it doesn't display the contents in the list.Kindly copy and compile the code, it's working but it doesn't display the contents in the list.
As I see, there are a number of issues with your code.
do not use conio.h. This thing is from the '80s and adds nothing to a modern program but problems
never try to implement an ADT --- any container such as list, set, map --- as a node. It will only give you trouble: a list is a collection of nodes. Each node has a payload, some data. This data can have a key, something used to compare records. A node is not a list. A node is not the data. A list is not a node. As seen from the list, the data are the nodes. This way you can use anything as data in your list. And this is the purpose of a container: write once, use always. And the list has metadata, some obvious controls such its size, starting addres, ending address and possibly other stuff.
do not use void(). Is a waste, sometimes an error. In your case is an error. All pointers are buried inside the functions and die there. So display() and add() does not work
do not typedef pointers. It is a mess. In you case manode is a pointer. How are someone, even yourself a few days from now, remember what is what? If manode is a typedef for a struct everyone knows that
manode* many_nodes[30]
declare many_nodes as a pointer to an array of structs. The asterisk tells everything: many_nodes is a pointer to manode. BTOS if you bury the * inside the typedef you will always need to refer to the code in the header.
do not mix code of the list with I/O. It will only make your like harder. You have a list of simple int, so declare add() for instance as int add(int item, List* the_list). This way is more readable and you can write a simple loop to fill the list with a few hundred or just one node and start testing.
if you have a menu just write it as a function that returns the user option. But add it later to the program. A menu serves nothing to the list and to the program
scanf() was not written to read input from the keyboard. It is for scan formatted input, hence the name. It will always give you trouble when reading from stdin. But do your part and at least always test the return of scanf(). ALWAYS. rtfm.
do not write \n \t on a printf. Use just tabs or count the spaces.
always initialize all variables. In your code you start testing choice and echoice with no value set.
what is the point of having a loop on option 1, add since anyway the user will need to input an answer and enter 1?
Back to your program
See below your code rearranged using some of the things I wrote above. Compare with your code
Sample Code
#include <stdio.h>
#include <stdlib.h>
typedef struct st_node
{
int data;
struct st_node* nextptr;
} Node;
typedef struct tlist
{
unsigned size;
Node* start;
} List;
int add(int, List*);
int delete (int, List*);
int display(List*);
int menu();
int main(void)
{
List one;
one.size = 0;
one.start = NULL;
int res = menu();
printf("menu returned %d\n", res);
display(&one);
for( int i = 0; i<10; i+=1)
add(i,&one);
display(&one);
return 0;
}
int add(int value, List* l)
{
if ( l == NULL ) return -1;
Node* node = (Node*) malloc(sizeof(Node));
// simplest: insert at the beginning
node->nextptr = l->start;
node->data = value;
l->start = node;
l->size += 1;
return l->size;
};
int display(List* l)
{
if ( l== NULL) return -1;
if ( l->size == 0 )
{
printf("\n\tlist is empty\n\n");
return 0;
}
else
{
printf("\n\t%d elements in the list\n\n", l->size);
};
Node* p = l->start;
for( unsigned i = 0; i< l->size; i+=1)
{
printf("%3d: %11d\n", 1+i, p->data);
p = p->nextptr;
};
return l->size;
}
int delete (int v, List* l)
{
return 0;
}
int menu()
{
int choice = 0;
int res = 0;
printf(
"\n\tENTER YOUR CHOICE FOR SINGLE LINKED LIST:\n\
\n\t\t1. ADD ELEMENT\
\n\t\t2. DISPLAY ELEMENT\
\n\t\t3. DELETE ELEMENT\
\n\t\t4. EXIT\
\n\n\t\tYour choice: ");
while( res != 1 )
{
res = scanf("%d", &choice);
if ( choice >=1 && choice <= 4 ) return choice;
};
return 4;
}
OUTPUT
ENTER YOUR CHOICE FOR SINGLE LINKED LIST:
1. ADD ELEMENT
2. DISPLAY ELEMENT
3. DELETE ELEMENT
4. EXIT
Your choice: 2
menu returned 2
list is empty
10 elements in the list
1: 9
2: 8
3: 7
4: 6
5: 5
6: 4
7: 3
8: 2
9: 1
10: 0
And it is just an example of stuff using a more manageable list.
I have been tasked with implementing an insert function which will be used in a project. If user input is 1 2 3 4, the desired output of the print statement would be 1, 2, 3, 4. Currently, my print statement is returning 4, 3, 2, 1 but I believe this to be correct. I think my issues lie within my input function (which is nested within a while loop to get user input). This is using C
Any help would be appreciated.
struct set {
int data;
struct set* next_p;
};
struct set* getInput( struct set* head_p, int val ) {
struct set* temp;
temp->data = val;
temp->next_p = head_p;
return temp;
} /* getInput */
struct set* makeSet( struct set* head_p ) {
int val;
printf( "Please enter a positive integer, or a negative to stop: \n" );
scanf("%d", &val);
while ( 100 ) {
head_p = getInput( head_p, val );
scanf("%d", &val);
}
return head_p;
}
Sorry mate was busy but hey i fixed your code.I already mentioned the problem was that you were appending the newNode before the head.
#include <stdio.h>
#include <stdlib.h>
struct set {
int data;
struct set* next_p;
};
struct set* getInput( struct set* ptr, int val )//appends a newNode to ptr which is the last node of Linked list
{
struct set* temp=NULL;
temp = (struct set*)malloc(sizeof(struct set));
temp->data = val;
temp->next_p = NULL;
if(ptr!=NULL)//if Linked list has been created,i.e.,only if we have a head run this
ptr->next_p=temp;
return temp;
} /* getInput */
struct set* makeSet( struct set* head_p ) {
int val;
struct set* ptr=head_p;
printf( "Please enter a positive integer, or a negative to stop: \n" );
while (1) {
scanf("%d", &val);
if(val>=0)
ptr=getInput( ptr, val );//appends only value>=0 to linked list else breaks from the infinite loop
else
break;
if(head_p==NULL)//To set the head of the linked List! True only for the 1st node in the linked list
head_p=ptr;
}
return head_p;
}
void display(struct set* head_p)
{
if(head_p==NULL)
printf("\nno List in Memory\n"); //
else
{
struct set* ptr=head_p;
printf("\n the linked list is\nHead");
while(ptr!=NULL)
{
printf("-->%d",ptr->data);
ptr=ptr->next_p;
}
}
}
int main()
{
struct set* head_p=NULL;
head_p=makeSet((head_p));//returns the head of the linked list created
display(head_p);//displays the linked list
return 0;
}
struct set* make_aSet(int val ) {
struct set* temp;
if((temp = malloc(sizeof(*temp))) != NULL){
temp->data = val;
temp->next_p = NULL;
} else {
fprintf(stderr, "can't make new a set\n");
}
return temp;
}
struct set* makeSet(void) {
struct set dummy_head, *current = &dummy_head;
int val;
printf( "Please enter a positive integer, or a negative to stop: \n" );
while (1==scanf("%d", &val) && val >= 0 ) {
current->next_p = make_aSet( val );
current = current->next_p;
}
return dummy_head.next_p;
}
code print elements after store them :
void print(struct node* root)
{
while ( c != NULL )
{
printf( "\n%d ", c->line1);
printf( "%s", c->curr );
c = c->next;
}
}
print method
Just looking at the code, this line seems like a potential issue:
temp->curr=current_input;
It looks like all the nodes .curr will get set = current_input. I'm guessing you need to do something like:
temp->curr = malloc(1 + strlen(current_input));
strcpy(tmp->curr, current_input);
Use strcpy_s if strcpy causes a warning.
First you should realize a list consists of nodes, which contain pieces of your data — so you need to allocate a new node for each piece of data you want to store in a list.
Then you insert each newly created node into the list and finally print the list when done.
Additionaly remember that data need to be either copied into the node (like line1) or copied somewhere else, for example onto the heap, and then linked to the node with a pointer, like curr (see the answer by #rcgldr).
struct node *root = NULL;
struct node *createnode(int line, const char *input)
{
struct node *n = malloc(sizeof(struct node));
if(n != NULL)
{
n->line1 = line;
n->curr = input;
n->next = NULL;
}
return n;
}
void insertnode(struct node* n)
{
n->next = root;
root = n;
}
void printlist(struct node* n)
{
for( ; n != NULL; n = n->next)
{
printf( "%d: %s\n", n->line1, n->curr);
}
}
int main(int argc, const char * argv[])
{
char *input;
struct node *temp;
type t;
do
{
t=getword(); //call to get the type of t
switch (t)
{
case number:
case keyword:
input = strdup(current_input); // make a copy of user input
if(input != NULL)
{
temp = createnode(line, input);
if(temp != NULL) // created?
insertnode(temp); // insert into the list
else
{
free(input); // free unused input copy
t = EOF; // make the loop terminate
}
}
else // user input copy failed
t = EOF; // make the loop terminate
break;
default:
break;
}
}
while (t != EOF);
print(root);
return 0;
}
I start by saying I am quite new to C and right now, I struggle with some very non intuitive mistakes. I've tried for quite a while now to reach at some solution, but I am always reaching a dead end.
I am trying to build a couple of functions for inserting and displaying a graph via dynamic linked lists. At compile time everything works just fine, but the elements seem not to be well displayed. Actually, just like in the image below, only the first element of the node is displayed.
So the question is what is causing these errors and warnings and what should I do to remove them?
If you take a look at the code below, you will see that it has a few warnings(I don't know why they appear - I am using Code Blocks in Ubuntu with the GNU compiler) and also problems at displaying the elements of the graph. The problem lies most likely in the display_graph function, but I can't realize where.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct AdjListNode {
int dest;
struct LIST_NODE *next;
} LIST_NODE;
typedef struct AdjList {
struct LIST_NODE *head;
} ADJACENCY_LIST;
LIST_NODE *create_node(int dest) {
LIST_NODE *nod;
if(dest<0) exit(0);
nod = (LIST_NODE*)malloc(sizeof(LIST_NODE));
if(nod==NULL) {
printf("Problems at memory allocation!");
exit(0);
}
nod->dest = dest;
nod->next = NULL;
return (LIST_NODE*)nod;
}
void display_graph(ADJACENCY_LIST *v) {
int s, i;
LIST_NODE *nod;
s = sizeof(v);
for(i=0;i<=s;i++) {
nod = v[i].head;
//citeste lista cu head in primul nod
while(nod!=NULL) {
printf("Data from node: %d \n", nod->dest);
nod = nod->next;
}
}
}
int main()
{
int n; //number of graph nodes
int i; //just a counter
int dest; dest = -1; //it's actually the "name" of the nodes. They must all be positive so I started negative
char c;
ADJACENCY_LIST *t;
printf("The number of nodes of the graph: ");
scanf("%d", &n);
t = (ADJACENCY_LIST*)malloc(n*sizeof(ADJACENCY_LIST));
/* We make a loop for the nodes and each node has a while thru which I make the links */
for(i=0;i<n;i++) {
c = 'D'; // Initializing
printf("Specify the links of the node %d with the others:\n", i);
int contor; contor = 0;
while(c=='D') {
LIST_NODE *nod;
printf("The link with node: ");
scanf("%d%*c", &dest);
if(dest>=0){
nod = create_node(dest);
if(contor==0) t[i].head = (LIST_NODE*)nod; // just make the first node a head node
} else nod = NULL;
//verificam daca vrem sa continuam
printf("Do you want to link any other node to %d?(D to add, anything else STOP\n)", i);
c = getchar();
contor++; //increment counter
}
// inchidem lista
}
display_graph(t);
return 0;
}
Any help will be greatly appreciated!
EDIT:
As Christhofe(confirmed the problem) and Abhishek Vasisht pointed out the size of the vector v returned actually the size of the pointer.
But, there are still some warnings which I don't know why they still appear...all are
||=== Build: Debug in Grafuri1 (compiler: GNU GCC Compiler) ===|
/home/marianpc/Anul_1/SDA/Grafuri1/main.c||In function ‘display_graph’:|
/home/marianpc/Anul_1/SDA/Grafuri1/main.c|33|warning: assignment from incompatible pointer type|
/home/marianpc/Anul_1/SDA/Grafuri1/main.c|38|warning: assignment from incompatible pointer type|
/home/marianpc/Anul_1/SDA/Grafuri1/main.c|28|warning: unused variable ‘s’ [-Wunused-variable]|
/home/marianpc/Anul_1/SDA/Grafuri1/main.c||In function ‘main’:|
/home/marianpc/Anul_1/SDA/Grafuri1/main.c|71|warning: assignment from incompatible pointer type|
/home/marianpc/Anul_1/SDA/Grafuri1/main.c|76|warning: assignment from incompatible pointer type|
||=== Build finished: 0 error(s), 5 warning(s) (0 minute(s), 0 second(s)) ===|
The main thing is the program is functional now. Thanks a lot guys! Really helpful!!
Try this
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct AdjListNode {
int dest;
struct LIST_NODE *next;
} LIST_NODE;
typedef struct AdjList {
struct LIST_NODE *head;
} ADJACENCY_LIST;
LIST_NODE *create_node(int dest) {
LIST_NODE *nod;
if (dest < 0) exit(0);
nod = (LIST_NODE*)malloc(sizeof(LIST_NODE));
if (nod == NULL) {
printf("Problems at memory allocation!");
exit(0);
}
nod->dest = dest;
nod->next = NULL;
return (LIST_NODE*)nod;
}
void display_graph(ADJACENCY_LIST *v,int values) {
int s, i;
LIST_NODE *nod;
for (i = 0; i < values; ++i)
{
nod = v[i].head;
printf("Data from node: %d \n", i);
while (nod != NULL)
{
printf("Data : %d \n", nod->dest);
nod = nod->next;
}
}
}
int main()
{
int n; //number of graph nodes
int i; //just a counter
int dest; dest = -1; //it's actually the "name" of the nodes. They must all be positive so I started negative
char* c = (char*)(malloc(sizeof(char)));
ADJACENCY_LIST *t;
LIST_NODE *last_added;
printf("The number of nodes of the graph: ");
scanf("%d", &n);
t = (ADJACENCY_LIST*)calloc(n,sizeof(ADJACENCY_LIST));
/* We make a loop for the nodes and each node has a while thru which I make the links */
for (i = 0; i < n; i++) {
//c = 'D'; // Initializing
printf("Specify the links of the node %d with the others:\n", i);
int contor; contor = 0;
do {
LIST_NODE *nod;
printf("The link with node: ");
scanf("%d", &dest);
if (dest >= 0) {
nod = create_node(dest);
if (contor == 0)
{
t[i].head = (LIST_NODE*)nod; // just make the first node a head node
last_added = nod;
}
else
{
last_added->next = nod;
last_added = nod;
}
}
//verificam daca vrem sa continuam
printf("Do you want to link any other node to %d?(D to add, anything else STOP\n)", i);
fflush(stdin);
*c = getchar();
contor++; //increment counter
} while (*c == 'D');
}
display_graph(t,n);
return 0;
}
the following code compiles cleanly, works.
It does not have the capability of having a list of nodes for each entry in the first level list of pointers.
You can easily add that feature.
You also need to add the feature of passing each malloc'd node to free()
especially when an error has occurred
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct AdjListNode
{
int dest;
struct AdjListNode *next;
} ;
// declare list of pointers to nodes
static struct AdjListNode **head = NULL;
struct AdjListNode *create_node(int dest)
{
struct AdjListNode *nod;
nod = malloc(sizeof(struct AdjListNode));
if(nod==NULL)
{
perror(" malloc failed" );
printf("Problems at memory allocation!");
exit(-1);
}
// implied else, malloc successful
nod->dest = dest;
nod->next = NULL;
return nod;
} // end function: create_node
int main( void )
{
int n; //number of graph nodes
int i; //just a counter
int dest = -1; //it's actually the "name" of the nodes. They must all be positive so I started negative
printf("The number of nodes of the graph: ");
if( 1 != scanf("%d", &n) )
{ // then scanf failed
perror( "scanf for number of nodes failed" );
exit( -1 );
}
// implied else, scanf successful
// set ptr to list of node pointers
head = malloc(n*sizeof(struct AdjList*));
if( NULL == head )
{ // then malloc failed
perror( "malloc failed for list of pointers to nodes" );
exit( -1 );
}
// implied else, malloc successful
// initialize list of pointers (makes for easier cleanup, especially when a failure occurs
memset( head, 0x00, n*sizeof(struct AdjList*) );
/* We make a loop for the nodes and each node has a while thru which I make the links */
for(i=0;i<n;i++)
{
printf("Enter Dest value for %d of %d:", i, n);
if( 1 != scanf("%d", &dest) ) // note %d will skip over leading white space like newlines
{ // then scanf failed
perror( "scanf for dest value failed" );
exit(-1);
}
// implied else, scanf successful
if(dest>=0)
{
head[i] = create_node(dest);
}
else
{
printf( "Dest value must be >= 0\n" );
}
//verificam daca vrem sa continuam
// inchidem lista
} // end for
return 0;
} // end function: main