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

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.

Related

Finding three leaders from arrays

Thank you for visiting this question. I know this looks like a question from a book which it totally is. I couldn't find the solution for this anywhere and I cant get one thing. Supposedly the code compare things like studs[i].score within for loop, but why it can assign the value of studs[i].score to another element of the struct like say first.score? The same goes for studs[i].name = first.name the program wont even compile. Any input matter, have been sitting with this for a week.
Have a great day!
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct stud {
char name[50];
float score;
};
//Please do not modify struct stud
//You are only allowed to modify inside printThreeLeaders
void printThreeLeaders(struct stud studs[], int count) { //why is count here? C arrays do not carry any size indicator, we
//must explicitly pass the number of elements in as an argument
//Please do not modify the content of studs array
struct stud first, second, third;
//Your code here
for (int i=0;i<count;i++){
if (studs[i].score>third.score){
if(studs[i].score>second.score){
if (studs[i].score>first.score){
studs[i].score=first.score;
studs[i].name=first.name;
}
}studs[i].score=second.score;
studs[i].name=second.name;
}studs[i].score=third.score;
studs[i].name=third.name;
}
//Please find the top three highest scoring students on the leaderboard
//and print out their names and scores.
//You are allowed to use string functions such as strcmp or strcpy
//Although you might not need them
//Please do not modify the following code
printf("Leader board:\n");
printf("First place: %s, %.2f\n", first.name, first.score);
printf("Second place: %s, %.2f\n", second.name, second.score);
printf("Third place: %s, %.2f\n", third.name, third.score);
}
//Please do not modify main function
int main(void) {
struct stud students[20];
int stud_count = 0;
char temp_name[50];
float grade = 0;
printf("Enter a test score(-1 to quit), or\n");
printf("Enter a grade first, then a student's name\n");
scanf("%f", &grade);
while (grade != -1)
{
scanf("%s", temp_name);
students[stud_count].score = grade;
strcpy(students[stud_count].name, temp_name);
stud_count ++;
printf("Enter a test score(-1 to quit), or\n");
printf("Enter a grade first, then a student's name\n");
scanf("%f", &grade);
}
if(stud_count > 2) {
printThreeLeaders(students, stud_count);
}
return 0;
}
A few issues:
You do modify the studs array with: studs[i].score=second.score;
The three variables first, second, and third are uninitialized so you have UB (undefined behavior)
You don't need to use str* functions to copy the name if you copy the whole struct.
Here is the refactored code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct stud {
char name[50];
float score;
};
// Please do not modify struct stud
// You are only allowed to modify inside printThreeLeaders
void
printThreeLeaders(struct stud studs[], int count)
{
// why is count here? C arrays do not carry any size indicator, we
// must explicitly pass the number of elements in as an argument
// Please do not modify the content of studs array
// NOTE/BUG: first/second/third are _not_ initialized
#if 0
struct stud first, second, third;
#else
struct stud first = { .score = -1 };
struct stud second = { .score = -1 };
struct stud third = { .score = -1 };
#endif
// Your code here
for (int i = 0; i < count; i++) {
const struct stud *st = &studs[i];
float score = st->score;
if (score > first.score) {
third = second;
second = first;
first = *st;
continue;
}
if (score > second.score) {
third = second;
second = *st;
continue;
}
if (score > third.score) {
third = *st;
continue;
}
}
// Please find the top three highest scoring students on the leaderboard
// and print out their names and scores.
// You are allowed to use string functions such as strcmp or strcpy
// Although you might not need them
// Please do not modify the following code
printf("Leader board:\n");
printf("First place: %s, %.2f\n", first.name, first.score);
printf("Second place: %s, %.2f\n", second.name, second.score);
printf("Third place: %s, %.2f\n", third.name, third.score);
}
// Please do not modify main function
int
main(void)
{
struct stud students[20];
int stud_count = 0;
char temp_name[50];
float grade = 0;
printf("Enter a test score(-1 to quit), or\n");
printf("Enter a grade first, then a student's name\n");
scanf("%f", &grade);
while (grade != -1) {
scanf("%s", temp_name);
students[stud_count].score = grade;
strcpy(students[stud_count].name, temp_name);
stud_count++;
printf("Enter a test score(-1 to quit), or\n");
printf("Enter a grade first, then a student's name\n");
scanf("%f", &grade);
}
if (stud_count > 2) {
printThreeLeaders(students, stud_count);
}
return 0;
}
In the above code, I've used cpp conditionals to denote old vs. new code:
#if 0
// old code
#else
// new code
#endif
#if 1
// new code
#endif
Note: this can be cleaned up by running the file through unifdef -k
Here is the test input I used:
1 Fred
2 Bob
3 Alice
4 John
5 Mary
6 Frank
7 Abel
8 Cain
9 Peter
10 Kilroy
11 Smith
12 Jones
-1
Here is the [cleaned up] program output:
Leader board:
First place: Jones, 12.00
Second place: Smith, 11.00
Third place: Kilroy, 10.00
UPDATE:
Amazing, it does work. The problem was in initialization of first, second and third. With this edits it does work. My incorrect reasoning was that initialization happened at 'struct stud first second third'. –
JEDi455
C is all about minimalism and speed.
Initialization [of stack based variables] is not done by default for speed.
Here, for this problem, explicit initialization was needed.
But, in another problem, suppose we had (e.g.):
int x,y,z;
If we explicitly assign them values with:
/* some small blob of code unrelated to x/y/z ... */
x = funcA();
y = funcB(x);
z = funcC(x,y);
Then, we'd be cursing the compiler for wasting time by initializing them to default values, only to overwrite those values with our explicit code.
That is, if the compiler always treated:
int x,y,z;
as:
int x = 0, y = 0, z = 0;
We'd not want the compiler to "help" us in this way. That is, if we wanted the latter, we'd have written that.
C gives the programmers full control [and assumes they know what they're doing]. The compiler will try to help by flagging statements with errors or warnings, but it's often up to the programmer.

C program to add 2 polynomials and then displaying it

I am writing a C program to add 2 polynomials given by user then displaying it in a separate function but it is not adding anything. In fact, it is not giving any type of error message so I am very confused. I think the mistake can be in 'addpoly' function or display function. I don't know what I am doing wrong. Any type of help will be appreciated.
#include<stdio.h>
#include<stdlib.h>
#define MAX 3
struct polynomial
{
int coeff;
int exp;
struct polynomial *next;
};
typedef struct polynomial polynomial;
polynomial *p1=NULL,*p2=NULL,*p3=NULL, *head_address=NULL;
polynomial* create()
{
polynomial *head_address=NULL, *prev_address=NULL, *new_address=NULL;
int i;
for(i=0;i<MAX;i++)
{
new_address=(polynomial*)malloc(sizeof(polynomial));
printf("Enter coeff:\n");
scanf("%d",&new_address->coeff);
printf("Enter exp:\n");
scanf("%d",&new_address->exp );
new_address->next=0;
if(head_address==NULL){
head_address=prev_address=new_address;
}
else{
prev_address->next=new_address;
prev_address=new_address;
}}
return head_address; }
void polyadd(polynomial *p1, polynomial *p2,polynomial *p3)
{
//polynomial* p3=NULL;
while(p1->next!=NULL && p2->next!=NULL){
if(p1->exp > p2->exp){
p3->coeff=p1->coeff;
p3->exp=p1->exp;
p1=p1->next;
}
else if(p1->exp < p2->exp){
p3->coeff=p2->coeff;
p3->exp=p2->exp;
p2=p2->next;
}
else if(p1->exp==p2->exp){
p3->coeff=p1->coeff + p2->coeff;
p3->exp=p1->exp;
p1=p1->next;
p2=p2->next;
}
p3->next=(polynomial*)malloc(sizeof(polynomial));
p3=p3->next;
p3->next=NULL; }
while(p1->next || p2->next){
if(p1->next){
p3->exp=p1->exp;
p3->coeff=p1->coeff;
p1=p1->next;
}
else if(p2->next){
p3->exp=p2->exp;
p3->coeff=p2->coeff;
p2=p2->next;
}
p3->next=(polynomial*)malloc(sizeof(polynomial));
p3=p3->next;
p3->next=NULL;
}
}
void display(polynomial *temp){
polynomial *p3;
p3=temp;
temp=head_address;
while(temp->next!=NULL)
printf("%dx^%d",temp->coeff,temp->exp);
temp=temp->next;
if(temp->next!=NULL){
printf(" + ");
}
}
int main(){
polynomial *p1,*p2,*p3;
p1=create();
printf("Next:\n");
p2=create();
polyadd(p1,p2,p3);
printf("Result:\n");
display(p3);
return 0;
}
Your issue looks like a memory reference error. In your polyadd() function you're not mallocing as much as you need to. Your base p3 pointer for your linked list is still unallocated when you start referencing off it in your first while loop. To fix your memory issue you'll want to malloc p3 before using it and then make sure the subsequent ->next instances all get malloced before being used.
I don't think this is causing you issues currently but you also have global variables defined at the top and then defined again in main(). The local variables will be the only ones used as long as they're present but I would delete your globals and make sure you don't have unused duplicates to avoid confusion.

Delete Single Student from Linked List

I cannot get this function to work properly. It crashes when I try to delete a specific record. What do I need to change for it to work as expected?
//Delete Students Function
void delete_single_Student(Student *pfirst, int id)
{
int search_id;
bool found = false;
Student *pcurrent = pfirst;
Student *temp = NULL;
printf("Please enter the student ID of the student that will be deleted.\n");
scanf("%d", &search_id);
while (search_id < 999 || search_id > 9999)
{
printf("\nPlease enter a valid id.\n");
scanf("%d", &search_id);
}
do
{
temp = pcurrent;
pcurrent = pcurrent->next;
if (pfirst->id == search_id)
{
found == true;
printf("**********************\n\n");
printf(" Student %d Deleted \n\n", search_id);
printf("*********************\n\n");
pfirst = pfirst->next;
free(temp);
break;
}
} while (found != true);
}
Notice that you are querying pfirst, but you are not generally changing pfirst in your loop. The conditional will only be true if the first element is your result. Additionally, found != true is always true, so you are bound to end up with a pcurrent null pointer after traveling the list and upon referencing pcurrrent->next, you bomb.
I would suggest that you incrementally attack with easier problems.
1) Just write a procedure to print each element, terminating when the pointer is null. You do not need a found variable.
2) Repeat number #1 but print that element side by side with its predecessor, requiring you to track the previous element.
3) After mastering #2, you will see that the first element is a special case and that you cannot really solve the problem without having access to the information that the calling function had.

Inserting in Linked List

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.

How to approach and optimize code in C

I am new to C and very much interested in knowing how to approach any problem which has more than 3 or 4 functions, I always look at the output required and manipulate my code calling functions inside other functions and getting the required output.
Below is my logic for finding a students record through his Id first & then Username.
This code according to my professor has an excessive logic and is lacking in many ways, if someone could assist me in how should I approach any problem in C or in any other language it would be of great help for me as a beginner and yes I do write pseudo code first.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct{
int id; //Assuming student id to be unique
int age;
char *userName; //Assuming student userName to be unique
char *dept;
}student; // Alias "student" created for struct
student* createstruct(); // All function prototype declared
student* createArray();
void addstruct(student* s2);
void searchChar(student* s2,int num);
void searchInt(student* s2,int num);
student* createstruct() // function createStruct() to malloc data of struct student.
{
student *s;
s = (student*)malloc(sizeof(student));
s->userName = (char*)malloc(sizeof(char)*32);
s->dept = (char*)malloc(sizeof(char)*32);
printf("please enter id ");
scanf("%d",&s->id);
printf("please enter age ");
scanf("%d",&s->age);
printf("please enter userName ");
scanf("%31s",s->userName);
printf("please enter department ");
scanf("%31s",s->dept);
printf("\n");
return s;
}
student* createArray()
{
student *arr; //declaration of arr poiter, type struct student
arr = (student*)malloc(sizeof(student)*10); // memory allocated for a size of 10
return arr;
}
void addstruct(student *s2) // function for adding data to the structures in array
{
int i,num;
student* s1;
printf("please enter the number of records to add:");
scanf("%d",&num);
printf("\n");
if(num>0 && num<11)
{
for(i=0;i<num;i++) // if user want to enter 5 records loop will only run 5 times
{
s1 = createstruct();
s2[i].id = s1->id; // traversing each element of array and filling in struct data
s2[i].age = s1->age;
s2[i].userName = s1->userName;
s2[i].dept= s1->dept;
}
}
else if(num>10) // if user enters more than 10
{
for(i=0;i<10;i++) // loop will still run only 10 times
{
s1 = createstruct();
s2[i].id = s1->id;
s2[i].age = s1->age;
s2[i].userName = s1->userName;
s2[i].dept = s1->dept;
}
printf("Array is full"); // Array is full after taking 10 records
printf("\n");
}
searchInt(s2,num); // Calling searchInt() function to search for an integer in records
searchChar(s2,num); // Calling searchChar() function to search for a string in records
free(s1);
free(s2);
}
void searchChar(student* s2,int num) // function for searching a string in records of structure
{
char *c;
int i;
c = (char*)malloc(sizeof(char)*32);
printf("please enter userName to search ");
scanf("%31s",c);
printf("\n");
for (i=0;i<num;i++) //num is the number of struct records entered by user
{
if ((strcmp(s2[i].userName,c)==0)) //using strcmp for comparing strings
{
printf("struct variables are %d, %d, %s, %s\n", s2[i].id,s2[i].age,s2[i].userName,s2[i].dept);
break;
}
else if(i == num-1)
{
printf("nothing in userName matches: <%s>\n",c);
break;
}
}
}
void searchInt(student* s2,int num) //searchs for an integer and prints the entire structure
{
int i,z;
printf("please enter id to search ");
scanf("%d",&z);
printf("\n");
for (i=0;i<num;i++)
{
if (s2[i].id == z)
{
printf("struct variables are %d, %d, %s, %s\n\n", s2[i].id,s2[i].age,s2[i].userName,s2[i].dept);
break;
}
else if(i == num-1)
{
printf("nothing in id matches: <%d>\n\n",z);
break;
}
}
}
int main(void)
{
student *s2;
s2 = createArray();
addstruct(s2);
return 0;
}
I'm not going to go into optimizing, because if you wanted better theoretical performance you would probably go with different data structures, such as ordered arrays/lists, trees, hash tables or some kind of indexing... None of that is relevant in this case, because you have a simple program dealing with a small amount of data.
But I am going to tell you about the "excessive logic" your professor mentioned, taking your searchInt function as an example:
for (i=0;i<num;i++)
{
if (s2[i].id == z)
{
printf("struct variables are %d, %d, %s, %s\n\n", s2[i].id,s2[i].age,s2[i].userName,s2[i].dept);
break;
}
else if(i == num-1)
{
printf("nothing in id matches: <%d>\n\n",z);
break;
}
}
The thing here is that every time around the loop you're testing to see if you're at the last element in the loop. But the loop already does that. So you're doing it twice, and to make it worse, you're doing a subtraction (which may or may not be optimized into a register by the compiler).
What you would normally do is something like this:
int i;
student *s = NULL;
for( i = 0; i < num; i++ )
{
if( s2[i].id == z ) {
s = &s2[i];
break;
}
}
if( s != NULL ) {
printf( "struct variables are %d, %d, %s, %s\n\n",
s->id, s->age, s->userName, s->dept );
} else {
printf("nothing in id matches: <%d>\n\n",z);
}
See that you only need to have some way of knowing that the loop found something. You wait for the loop to finish before you test whether it found something.
In this case I used a pointer to indicate success, because I could then use the pointer to access the relevant record without having to index back into the array and clutter the code. You won't always use pointers.
Sometimes you set a flag, sometimes you store the array index, sometimes you just return from the function (and if the loop falls through you know it didn't find anything).
Programming is about making sensible choices for the problem you are solving. Only optimize when you need to, don't over-complicate a problem, and always try to write code that is easy to read/understand.

Resources