Inserting in Linked List - c

I'm having a small difficulty inserting a full sentence containing all characters in my string when I'm building a Linked List.
I would like to be able to insert a string like: word_#_2003_#_definition
But when I'm running my code in my main() method it continues repeating the choices to do like it never stops asking me to enter an option. Hope it's clear.
Here's my struct:
struct node
{
char data[100];
struct node *previous; // Points to the previous node
struct node *next; // Points out to the next node
} *head, *last;
Here's my function to insert a node:
void insert_beginning(char words[99])
{
struct node *var, *temp;
var=(struct node *)malloc(sizeof(struct node)); //explination about the (node *)
strncpy(var->data, words,99);
if (head==NULL)
{
head=var;
head->previous=NULL;
head->next=NULL;
last=head;
}
else
{
temp=var;
temp->previous=NULL;
temp->next=head;
head->previous=temp;
head=temp;
}
}
And this is in my main() method:
int main()
{
char loc[99];
char words[99];
int i, dat;
head=NULL;
printf("Select the choice of operation on link list");
printf("\n1.) Insert At Begning\n2.) Insert At End\n3.) Insert At Middle");
printf("\n4.) Delete From End\n5.) Reverse The Link List\n6.) Display List\n7.)Exit");
while(1)
{
printf("\n\n Enter the choice of operation you want to do ");
scanf("%d",&i);
switch(i)
{
case 1:
{
printf("Enter a word you want to insert in the 1st node ");
scanf(" %s",words);
insert_beginning(words);
display();
break;
}
Any ideas on how to do it?

The code is highly questionable:
return codes are never checked. You must check return codes,
especially if you are using scanf
You need to empty the whole buffer with scanf otherwise you will continue
reading old contents for the next command
A better alternative is to use sscanf
You must initialize your variables, for instance last, but there are additional
cases of variables that do not get initialized
Your data types are not consistently defined, this will create security problems
sometimes 99 characters and sometimes 100.
insert_beginning should not return void, the memory allocation can fail

Your code in main() should probably look more like:
int main()
{
char loc[99];
char words[99];
int i, dat;
head = NULL;
printf("Select the choice of operation on link list");
printf("\n1.) Insert At Beginning\n2.) Insert At End\n3.) Insert At Middle");
printf("\n4.) Delete From End\n5.) Reverse The Link List\n6.) Display List\n7.) Exit\n");
while(1)
{
printf("\nEnter the choice of operation you want to do: ");
if (scanf("%d", &i) != 1)
{
fprintf(stderr, "Failed to read a number: exiting\n");
return 1;
}
switch(i)
{
case 1:
{
printf("Enter a word you want to insert in the 1st node: ");
if (scanf("%98s", words) != 1)
{
fprintf(stderr, "Failed to read words; exiting\n");
return 1;
}
insert_beginning(words);
display();
break;
}
...
}
...
}
...
}
return 0;
}
As discussed in the comments, you are not checking the return status from scanf(), so you don't know when it is failing, and when it fails to read a number, it leaves the argument (i) alone, so you go back to the same option again, and rinse and repeat.
Elementary debugging techniques (not shown):
Print the values you get from your inputs. Print the value of i after the scanf() error checking. Print the value of words after the scanf() error checking.
Step through with a debugger.
Create a function to dump (print) your key data structures:
static void dump_data_structure(FILE *fp, char const *tag, data_structure const *data)
{
...code to dump the structure to the specified file stream,
...identified by tag (so you can tell which call it is you are looking at)
}
Use the structure dumper extensively while debugging. Keep it for use later when modifying the code. If done right, it can be enormously helpful.

Related

Issue with C, program prints values that aren't supposed to print

I've been trying to find an issue with this code for a few days but I still can't find it. The main problem here is that, when printing the values of each node, it tries to print an extra node and makes up new values.
The code works the following way, for example: I put numbers 10,11,15 and if the sum of all three numbers of the node is more than 20 then it adds the double before so the result would be: 20,22,30 || 10,11,15.
Every time I try to execute this code in Visual Studio Code the program prints:
20,22,30 || 10,11,15 || 0,26345856,301989906. As you can see, the program tries to print another node that doesn't exist so it makes up values. I've tried on some online compilers and this isn't a problem, so what I would like to know is if there is any error in my code or if it's the compiler.
#include <stdio.h>
#include <stdlib.h>
typedef struct list{
int num;
int num1;
int num3;
struct list *next;
}node;
void create (node *p){
printf("Input first number: ");
scanf("%d",&p->num);
if (p->num==0)
p->next=NULL;
else{
printf("Input second number: ");
scanf("%d",&p->num1);
printf("Input third number: ");
scanf("%d",&p->num3);
p->next=(node*)malloc(sizeof(node));
create (p->next);
}
}
void show (node *p){
if (p->next !=NULL){
printf ("\n%d",p->num);
printf ("\n%d",p->num1);
printf ("\n%d",p->num3);
show (p->next);
}
}
node* add(node *p){
node *aux;
if((p->num+p->num1+p->num3)>20){
aux=(node *)malloc(sizeof(node));
aux->num=p->num*2;
aux->num1=p->num1*2;
aux->num3=p->num3*2;
aux->next=p;
p=aux;
}
return p;
}
void add2 (node *p){
node *aux=NULL;
while(p->next!=NULL){
if((p->next->num +p->next->num1+ p->next->num3)>20){
aux=(node *)malloc(sizeof(node));
aux->num=p->next->num*2;
aux->num1=p->next->num1*2;
aux->num3=p->next->num3*2;
aux->next=p->next;
p->next=aux;
p=p->next;
}
p=p->next;
}
}
int main(){
node *prin=NULL;
prin=(node*)malloc(sizeof(node));
create(prin);
printf("Input numbers were: ");
show (prin);
prin=add(prin);
add2(prin->next);
printf("\nList with added nodes: ");
show(prin);
}
You are always creating a 'dummy' node at the foot of your list. For example, if you enter 0 as the very first input, you will have a single-entry list where only the num (set to that 0) and next (set to NULL) members are initialized. The num1 and num3 fields are left uninitialized by the create function. Likewise if, as in your given test case, you enter (and initialize) actual values for those last two fields, you will still have created a new 'foot' node in the next call to create.
As it happens, on your system, these uninitialized data fields have 'random' values that, together, add up to more than 20. (This is perfectly allowable by the C standard, but some compilers and/or platforms will, by default, set that uninitialized data to zero.)
Thus, in your call to the add function, the if test condition in:
if ((p->num + p->num1 + p->num3) > 20) {
//...
will evaluate to TRUE and a new node will be added, with num1 and num3 having values twice that of the original 'random' values.
To fix the problem, set the num1 and num3 fields to zero (or some other small/negative numbers) in your create function, when the 'sentinel zero' end-of-input mark is entered for the num field:
void create(node* p)
{
printf("Input first number: ");
scanf("%d", &p->num);
if (p->num == 0) {
p->next = NULL;
p->num1 = 0; // You MUST ensure that the sum of these two numbers
p->num3 = 0; // is LESS THAN 20 ... or a new node will be created
}
else {
printf("Input second number: ");
scanf("%d", &p->num1);
printf("Input third number: ");
scanf("%d", &p->num3);
p->next = (node*)malloc(sizeof(node));
create(p->next);
}
}
EDIT: To see how this 'bug' is happening, try just setting the num1 field to a specific number (say, 42) and leaving num3 uninitialized. Then, only one of the 'made up' values will be unexplained - the other one will be twice what you have specified (so, 84). This would make a good exercise, IMHO.

Printing the structure of n-ary array in C

My homework for my c course is to implement a menu as a n-ary tree. I have to create a struct, populate it with data and print the data.
Although creating a struct and populating were relatively easy, I have found the struggle with printing. My goal is to print the structure in this manner:
1 File
1.1 Open
1.2 Save As
1.3 Save as Other
1.3.1 Text
1.3.2 Word or Excel Online
1.4 Send File
1.4.1 Attach to Email
1.4.2 Send & Track
1.5 Close
My struggle is that I can't find a way how to:
a) Add spaces after each child.
b) Add number for each child of the child.
My structure looks like this:
typedef struct node
{
long nodeID;
long parentNodeID;
char name[100];
struct node *next;
struct node *child;
} node;
My failed attempt to accomplish this :
void printMenu(node* root){
if(root == NULL) {
fprintf(stderr, "Root has not been initialised");
exit(1);
}
if(root->parentNodeID == 0){
printf("%ld %s",root -> nodeID,root -> name);
fflush(stdout);
printMenu(root->child);
}
if(root->child){
printf("%6ld.%ld %s",root->parentNodeID,root->nodeID - 1,root->name);
fflush(stdout);
printMenu(root->child);
}
printf("%5ld.%ld %s",root->parentNodeID,root->nodeID - 1,root->name);
fflush(stdout);
printMenu(root -> next);
}
Please send help :(
I would sugggest using recursion. Below is a coded up example of how that would work. You would need to call this function with spacing starting at 0. This also assumes that the parentID is the appropriate ID with the previous parent id's.
void printMenu(node* root, int spacing) {
if(root == NULL) {
return;
}
else {
for(int i =0; i < spacing; i++) {
printf(' ');
}
printf("%d.%d %s", root->parentNodeID, root->nodeID, root->name);
for(int i =0; i< sizeof(root->child); i++) {
printNodes(root->child[i], spacing+1);
}
}
}
Rather than long parentNodeID, use a pointer to the parent node:
typedef struct node
{
struct node *parent;
struct node *next;
struct node *child;
char *name;
long id;
} node;
The root level nodes (File, for example) have NULL parents.
This lets you use a simple recursive function to print the IDs. The only trick is that you need to recurse before printing:
void print_path(FILE *out, node *to)
{
if (to->parent) {
/* Non-root nodes */
print_path(out, to->parent);
fprintf(out, ".%ld", to->id);
} else
/* Root nodes */
fprintf(out, "%ld", to->id);
}
With this, printing the menu recursively is easy:
void print_menu(FILE *out, node *menu, int indent)
{
while (menu != NULL) {
/* Print indent first */
fprintf(out, "%*s", indent, "");
/* Current menu entry */
print_path(out, menu);
fprintf(out, " %s\n", menu->name);
/* Submenu? */
if (menu->child)
print_menu(out, menu->child, 3 + indent);
menu = menu->next;
}
}
If you have say node *all; that contains your menu tree, and you wanted to print it to standard output, just call print_menu(stdout, all, 0);.
Note that I like to explicitly specify the file handle used for output, rather than just assume it is always stdout. (fprintf(stdout, ..FOOBAR..) is equivalent to printf(..FOOBAR..).) This approach lets me use the exact same functions when printing to a file, you see.
Printing the indent via %*s is not magic. The * in the width field for the s conversion just means that printf() will take the width from an int parameter, before the actual string to be printed. Thus, printf("%*s", n, "") will print n spaces. It is often called a "trick", but really, it is just well-documented printf() behaviour.

Inserting at the end of queue in C

I am trying to insert node at the end of queue and facing below error . This is simple fundamental error while compiling the code but making my life hard.
#include<stdio.h>
#include<stdlib.h>
typedef struct UNIX {
char str[20];
struct UNIX *next;
}examp;
examp *head=NULL;
int insert_last(char *s)
{
examp *new,*slide;
slide=head;
new = (examp *)malloc(sizeof(examp));
if(!new)
return(EXIT_FAILURE);
while(slide->next!=NULL)
slide=slide->next;
slide->next=new;
new->str=s;
new->next=NULL;
if(head==NULL)
{ head=new;
return 1;
}
return 1;
}
void display (void);
int main()
{
insert_last("hello ");
insert_last("how ");
insert_last("have ");
insert_last("you ");
insert_last("been ");
insert_last("! ");
display();
}
void display(void)
{
examp *slide;
slide=head;
while(slide->next!=NULL)
{ printf("%s ",slide->str);
slide=slide->next;
}
}
Error :stack_queue.c:27:10: error: assignment to expression with array type
new->str=s;
Update : Using strncpy reolved the error , but code is not working as expected and stopping unexpectedly.
You can't assign to a static array like that. Consider using strcpy or strncpy to copy the contents of the character string instead.
You cannot assign a string to an array! An array have its own memory, you can write or read elements in the array, but cannot assign an address.
You can eventually copy the string s contents to the array:
strncpy(new->str, s, 19);
new->str[19] = '\0'; //Close the string in case of overflow.
We used strncpy to limit the copied characters to the array size (19 chars + the ending '\0').
You can try it. Only replace in new->str=s; to strcpy(new->str, s); (ie. s will be copy in to new->str)
#include<stdio.h>
#include<stdlib.h>
typedef struct UNIX {
char str[20];
struct UNIX *next;
}examp;
examp *head=NULL;
int insert_last(char *s)
{
examp *new,*slide;
slide=head;
new = (examp *)malloc(sizeof(examp));
if(!new)
return(EXIT_FAILURE);
while(slide->next!=NULL)
slide=slide->next;
slide->next=new;
strcpy(new->str, s);
new->next=NULL;
if(head==NULL)
{ head=new;
return 1;
}
return 1;
}
void display (void);
int main()
{
insert_last("hello ");
insert_last("how ");
insert_last("have ");
insert_last("you ");
insert_last("been ");
insert_last("! ");
display();
}
void display(void)
{
examp *slide;
slide=head;
while(slide->next!=NULL)
{ printf("%s ",slide->str);
slide=slide->next;
}
}
As already stated you will have to use strcpy (or strncpy) in order to assign the string.
Asides from that I wanted to mention two things:
Do not forget to free your memory allocated by malloc. Create a method to free a single node (examp) then you can also provide a method to destroy the whole list.
I would suggest to rename the variable new to avoid confusion (pure C compiler may deal with it, but C/C++ compiler will most likely get into trouble).
Considering your update:
Take a look at the following line
while(slide->next!=NULL)
At this time slide does not even exist (it is NULL), still you perform an operation on the pointer. This is the reason why the program crashes.
Your error is in the first call insert_last("hello "):
int insert_last(char *s)
{
examp *new,*slide;
slide=head;
new = (examp *)malloc(sizeof(examp));
if(!new)
return(EXIT_FAILURE);
while(slide->next!=NULL)
slide=slide->next;
when you call it first time, head is NULL, so slide becomes NULL, but you don't check it, and call it in
while(slide->next!=NULL)
Here slide is null for the frst function call

How to make sure user input is unique

in my program I want to make sure that the 'identifier' String the user inputs is unique, for a new Book object they are creating. I think a While loop is the way to go , and have it keep asking the user to input a an identifier until it doesn't match an existing one. Really struggling to find a way to make it work, so if anyone can point me in the right direction i'd really appreciate it. Thanks!
Im using a Linked List structure by the way..
void addBook(){
struct node *aNode;
struct book *aBook;
struct node *current, *previous;
bool identifierIsTaken = true;
char identifierInput[10];
current = previous = front;
aBook = (struct book *)malloc(sizeof(struct book));
while(identifierIsTaken){
printf("Enter identifier for new book: ");
scanf("%s", identifierInput);
if(!strcmp(identifierInput, current->element->identifier) == 0){
identifierIsTaken = false;
strncpy(aBook->identifier, identifierInput, 10);
}
else
previous = current;
current = current->next;
}
printf("Enter book name: ");
scanf("%s", &aBook->name);
printf("Enter author: ");
scanf("%s", &aBook->author);
..........
The loop seems to work only once when I enter an occupied identifier, but then if I try again it falls through and the identifier is taken.
It's better to write a separate function to check identifier is unique or not.
int isUnique(char *identifierInput,struct node start)
{
while(start != NULL) {
if(strcmp(identifierInput, start->element->identifier) == 0) {
//string already present,return 0.
return 0;
}
start = start->link;
}
//we reached end of linked list.string is unique.return 1.
return 1;
}
From your main you call this function,
sudo code
int main()
{
:
:
:
while(i<number_of_item){
printf("Enter identifier for new book: ");
scanf("%s", identifierInput);
if(isUnique(identifierInput,current)){
//add it to the linked list.do whatever you want here.
} else {
// it is not unique.do what ever you want here.
}
}
:
:
:
}
Hope it will be helpful.

hangman console game in c

#include<stdio.h>
#include<string.h>
#include<time.h>
#include<stdlib.h>
typedef struct dic {
int index;
char string[10];
struct dic *next;
}node;
main() {
FILE *fp;int indexrand;node *head;node *mainhead;
char s[10],question[10],answer[10];char check;
int count=-1,i,j,k,len,flag;head=(node *) malloc(sizeof(node));
mainhead=head;
fp=fopen("dictionary.txt","r");
while((fgets(s,10,fp))!=NULL) {
strcpy(head->string,s);
count++;
(head->index)=count;
head->next=(node *)malloc(sizeof(node));
head=head->next;
}
fclose(fp);
head->next=NULL;
srand(time(NULL));
indexrand=rand()%(count+1);
printf("%d\n",indexrand);
for(head=mainhead;(head->next)!=NULL;head=head->next)
if((head->index)==indexrand)
strcpy(question,(head->string));
printf("%s\n",question);
len=strlen(question);
printf("%d\n",len);
for(i=0;i<len-1;i++)
answer[i]='_';
answer[i]='\0';
printf("%s\n",answer);
printf("6 chances to go\n");
for(i=0,k=6;k>0;i++) {
flag=0;
printf("%d\n",i);
scanf("%c",&check);
for(j=0;j<(len-1);j++) {
if(question[j]==check) {
flag++;
answer[j]=check;
}
}
if(flag>0)
printf("%d chances to go\n",k);
if(flag==0) {
k--;
printf("no common letters...%d chances to go\n",k);
}
printf("%s\n",answer);
}
}
The file dictionary.txt has only one word per line.
While running the code, for every attempt from the user (i.e after user enters a character) the statement no common letters...%d chances to go\n",k is being displayed even if the flag > 0 condition is satisfied.
How do I correct this?
The line
scanf("%c",&check);
is reading characters the user types, including the newline.
You probably just want to read the first character on the line: use fgets() to read the whole line, and then set check = line[0].
printf("%d\n",i);
scanf("%c",&check);
Because of these statements,scanf is taking \n as a parameter and so printing "no common letters..." every time.Replace the above code with
printf("%d",i);
scanf("\n%c",&check);
I think you want to pass a string to scanf, so try it :
scanf("%s",&check);

Resources