I just have a question(s) about making a binary tree, as this code doesn't work, it places nodes where they shouldn't go, and although it never crashes its leaking memory like a busted pipe. The idea was a simple guessing game where it simply tries to guess what you are thinking about, and when it gets it wrong you enter a question and answer to help it learn. Relevant code:
I guess my primary problem is char *guess will sometimes store only fragments of the original string passed to getnew(). The next would be the logic in traverse(), as it will jump to the "no" condition regardless of user input.
struct binary {
unsigned long ID;
char *guess;
char isAns;
struct binary *yes;
struct binary *no;
};
typedef struct binary Node;
void traverse(Node **top)
{
if(*top)
{
char ans[128] = "ok";
char ans2[128] = "ok";
if((*top)->isAns=='y')
{
fprintf(stdout,"Is it %s (y/n)? ",(*top)->guess);
}
else
{
fprintf(stdout,"%s (y/n)? ",(*top)->guess);
}
while(!fgets(ans,128,stdin));
if((*top)->isAns=='y')
{
if(ans=="y")
{
printf("Successful string of guesses!\n");
}
else
{
printf("Enter another question to figure out the difference: ");
while(!fgets(ans,128,stdin));
Node *q=getnew(ans,'n');
printf("Enter the right answer: ");
while(!fgets(ans2,128,stdin));
push1(top,q,'n');
(*top)->yes = getnew(ans2,'y');
}
}
else
{
if(ans=="y")
{
if((*top)->yes)
{
traverse(&(*top)->yes);
}
else
{
printf("Null node for top->yes\n");
printf("Enter an answer: ");
while(!fgets(ans,128,stdin));
(*top)->yes=getnew(ans,'y');
}
}
else
{
if((*top)->no)
{
traverse(&(*top)->no);
}
else
{
printf("Null node for top->no\n");
printf("Enter an answer: ");
while(!fgets(ans,128,stdin));
(*top)->no=getnew(ans,'y');
}
}
}
}
else
{
char ques[128] = "ok";
char ans[128] = "ok";
printf("Node is null\n");
printf("Put in a question and answer to yes condition\n");
printf("Enter question: ");
while(!fgets(ques,128,stdin));
printf("Enter answer for yes condition: ");
while(!fgets(ans,128,stdin));
(*top) = getnew(ques,'n');
(*top)->yes=getnew(ans,'y');
}
printf("\n\n");
}
Node * getnew(char *msg, char isAns)
{
Node *nnew = malloc(sizeof(Node));
nnew->ID=clock();
nnew->guess=malloc(sizeof(msg));
strcpy(nnew->guess,msg);
nnew->isAns=isAns;
nnew->yes=0;
nnew->no=0;
return nnew;
}
I appreciate any help.
nnew->guess=malloc(sizeof(msg)); only allocates enough memory for a pointer.
Instead of:
nnew->guess=malloc(sizeof(msg));
strcpy(nnew->guess,msg);
use:
nnew->guess=strdup(msg);
You probably want to use strdup
C strings are char * pointers, therefore `sizeof(msg) == sizeof(char*) == 8 or 4". Not what you want.
nnew->guess=malloc(sizeof(msg));
strcpy(nnew->guess,msg);
Should be
nnew->guess = strdup(msg);
Or
nnew->guess=malloc(strlen(msg) + 1);
strcpy(nnew->guess,msg + 1);
The +1 is for the nul termintor (assuming you want it).
I see where guess is malloced but I don't see where it's freed. That would definitely cause memory leaks.
as a side note, I've just spun up a quick program to check into the
nnew->guess=malloc(sizeof(msg));
it looks like this
char str[10] = "string";
printf("%d", sizeof(str));
and surprisingly, it printed 10,
but that method of allocation still makes me uneasy.
Related
The following code is supposed to insert the name of a good, whether it's getting stored or sent away (with just a single letter, like i for in or o for out) and in conclusion how much of that item is getting moved.
Then the program should end whenever I write the END phrase.
Problem is, I am finding a violation of access while trying to save the number of items, and cannot seem to find where I am doing something wrong.
#define MAX 20
#define END "FINE"
typedef struct type_struct {
char name[MAX];
char move[2];
int quantity;
struct type_struct* next;
}type;
void insert(type* p) {
type* aux;
aux = p;
while (aux != NULL)
aux = aux->next;
aux = malloc(sizeof(type));
printf("name of good: ");
scanf("%s", aux->name);
getchar();
printf("in or out?: ");
scanf("%c", aux->move);
printf("quantity: ");
scanf("%d", aux->quantity);
printf("\n");
}
int main(void) {
type* phrase=NULL;
char fine[5];
strcpy(fine, END);
do {
insert(phrase);
} while ((strcmp(phrase, fine) == 0));
}
It should be very simple, however, I am clueless and hope you might give me a hand
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
struct person {
char user[50];
char password[50];
int amount;
};
int i=0;
int h=0;
int *n=&h;
struct person *p = NULL;
void adduser();
int main()
{
int x;
printf("Welcome to the bank\n");
printf("what would you like to do\n");
printf("type 1 to add a user\n");
printf("type 2 to add to balance\n");
printf("type 3 to take from balance\n");
printf("type 4 to check from balance\n");
scanf("%d%*c",&x);
if(x==1){
adduser();
}
else if (x == 2){
printf("2");
}
else if (x == 3){
printf("3");
}
else if (x == 4){
printf("4");
}
else{
main();
}
}
void adduser(){
struct person *temp = realloc(p, *n * sizeof(struct person));
if (temp != NULL)
p = temp;
printf("n=%d\n",*n-1);
printf("enter your new username\n");
scanf("%s",&(p+*n)->user);
int o=*n-1;
for (i;i<=o;i++)
{
if(strcmp((p+*n)->user,(p+i)->user) == 0)
{
printf("user already exists");
adduser();
}
}
printf("enter your new password\n");
scanf("%s",(p+*n)->password);
*n+=1;
main();
}
hello I'm a beginner with C I'm trying to see i have string the user input similar to one in my structure using this code.
for (i;i<=o;i++)
{
if(strcmp((p+*n)->user,(p+i)->user) == 0)
{
printf("user already exists");
adduser();
}
}
my code is supposed ask the user to enter their new user(at least what i posted) and checks if a similar user exists but my loop gets ignored i don't know what to do with it . i feel like my problem lies elsewhere but i cant figure it out. Also i might have done fundamental mistakes because I'm very new to structures and pointers.
i tried searching online for solutions but i couldn't find a similar situation.
This code is clearly in error:
struct person *temp = realloc(p, *n * sizeof(struct person));
since we're almost immediately going to do:
scanf("%s",&(p+*n)->user);
this really needs to read
struct person *temp = realloc(p, (*n + 1) * sizeof(struct person));
In addition,
for (i;i<=o;i++)
is clearly wrong and should be
for (i=0;i<=o;i++)
and as dxiv points out, i really should be declared in this for loop rather than as a global.
Incidentally, are you having trouble with loops? I don't see that recursive call of main() much. It's really clever, but this code works well only if compiled with optimizations on (which in turn is harder to debug). I'd advise replacing
else{
main();
}
and the other calls to main() with an infinite loop around all of main() (which eventually will have a loop exit condition or a conditional break; statement on the input ladder.
I am trying to improve my C skills so I apologize if my question is long. I am having a hard time understanding as to why my struct pointer holds the wrong value in my program, I tried to debug it but I am still relatively new to C and was hoping one of you could tell me what I'm doing wrong here and how I could improve my code and what to focus on.
I am making a program that stores user data on this struct and then prints it out.
typedef struct table {
char *firstName;
char *lastName;
int id;
}USER;
This function below stores the first name
void firstName(int *counter, int *check, USER *pt) {
for (int i = *counter; i < *check; i++) {
pt[i].firstName = calloc (MAX_LENGTH, sizeof(pt));
printf("Enter First Name: ");
getchar();
fgets(pt[i].firstName, MAX_LENGTH, stdin);
}
}
This is just my bool function returning true or false
bool isTrue(char *decision) {
if(*decision == 'Y') {
return true;
}
else {
return false;
}
}
And this is my main
int main(int argc, char **argv) {
USER *pt = calloc(1, sizeof(pt));
int counter = 0, check = 0;
char decision = '\0';
while (1) {
printf("Would you like to enter a user?(Y/N):");
fgets(&decision, 2, stdin);
strtok(&decision, "\n"); //remove the newline char
if (!isTrue(&decision)) {
break;
}
if (counter != 0) {
pt = realloc(pt, sizeof(pt) * 10); //the 10 is temporary
}
check = counter + 1; // make sure loop only runs once.
firstName(&counter, &check, pt);
++counter; // increment counter;
}
printStruct(pt, &counter);
return 0;
}
When I run it out sometimes it works fine and returns everything and sometimes it skips a value. This is what I get. It skips the value at pointer index 1 and prints garbage instead.
Would you like to enter a user?(Y/N):N
First name at array 0 is Ermir
First name at array 1 is P#1First name at array 2 is Kevin
First name at array 3 is Blaus
First name at array 4 is Adam
Also I was wondering why is it when I realloc here If i do I get a realloc error when I enter the second name.
if (counter != 0) {
pt = realloc(pt, sizeof(pt) * 10); //realloc(pt, sizeof(pt) * counter + 1) wont work
}
char decision = '\0';
...
fgets(&decision, 2, stdin);
You are only allocating 1 char but are at least reading 2 chars into it. Fix by allocating a sufficiently sized array for decision.
Unrelated but in firstName() pt[i].firstName = calloc (MAX_LENGTH, sizeof(pt)); should be pt[i].firstName = calloc (MAX_LENGTH, 1);
I prefer to create a Dictionary object and add 3 words to it.
My program has no compilation error but gets a run time error in the second for loop, is the problem in addNewWord function? Do I need pass a pointer to the DictionaryWord object ?
Please help me.
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#include<string.h>
typedef struct{
char* name;
char* mean;
} Words;
typedef struct{
Words* word;
int size;
} Dictionary;
Dictionary createNewDictionary();
Words createNewWord();
void addNewWord(Words newword, Dictionary dic);
Dictionary createNewDictionary(){
Dictionary dic;
dic.size = 0;
dic.word = (Words*)malloc(dic.size*sizeof(Words));
return dic;
}
Words createNewWord(){
Words newword;
newword.name = (char*)malloc(30*sizeof(char));
newword.mean = (char*)malloc(30*sizeof(char));
printf("============================\n");
printf("Enter word: ");
scanf("%[^\n]", newword.name);
fflush(stdin);
printf("\nEnter meaning: ");
scanf("%[^\n]", newword.mean);
return newword;
}
void addNewWord(Words newword, Dictionary dic){
dic.size++;
dic.word = (Words*)realloc(dic.word,dic.size*sizeof(Words));
strcpy(dic.word[dic.size-1].name, newword.name);
strcpy(dic.word[dic.size-1].mean, newword.mean);
}
int main(){
Dictionary d = createNewDictionary();
for (int i=0;i<3;i++){
addNewWord(createNewWord(), d);
}
return 0;
}
There are lots of problem with your code:
Given the longest word in English is around 30 characters, this size allocation is realistic for the word, but not for the defintion:
newword.name = (char*)malloc(30*sizeof(char));
newword.mean = (char*)malloc(30*sizeof(char));
This makes little obvious sense:
dic.size = 0;
dic.word = (Words*)malloc(dic.size*sizeof(Words));
you called malloc() on zero! You're only spared by your later realloc(). Even if intentional, it really deserves a comment.
This doesn't really work as fflush() is for output streams:
fflush(stdin);
see: How to clear input buffer in C? And whatever fix you use has to apply to both scanf() calls, not just one!
Per #Jarvis, this doesn't work:
dic.word = (Words*)realloc(dic.word,dic.size*sizeof(Words));
strcpy(dic.word[dic.size-1].name, newword.name);
strcpy(dic.word[dic.size-1].mean, newword.mean);
as you didn't allocate any space for name and mean in dic so you're copying into random memory.
Per #Jarvis, doesn't work:
void addNewWord(Words newword, Dictionary dic){
dic.size++;
dic.word = (Words*)realloc(dic.word,dic.size*sizeof(Words));
You're passing dic by value so inside addnewWord() you've a copy of dic so the original dic's size will be the same as it was before the call!
Memory leak:
addNewWord(createNewWord(), d);
you dropped your handle onto what createNewWord() returned so you can never free the memory it malloc()'d
You malloc() memory but provide no means to eventually free it.
Passing and returning structs by value is a disaster in a situation like this, as the data keeps getting copied. At the least it's inefficient, at worst its buggy like the size issue above. Rather than risk it, pretend they can only be passed and returned by pointer and you'll be playing it safe and get a better result.
Below is a rework of your code (in C) with fixes, style tweaks and an attempt at a consistent terminology. It also provides some minimal test code and the ability to free your data:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_WORD_LENGTH 30
#define MAX_DEFINITION_LENGTH 1024
typedef struct entry {
char *word;
char *definition;
} Entry;
typedef struct dictionary {
Entry *entries;
int num_entries, max_entries;
} Dictionary;
Dictionary *createNewDictionary() {
Dictionary *dictionary = malloc(sizeof(*dictionary));
dictionary->num_entries = 0;
dictionary->max_entries = 1;
dictionary->entries = calloc(dictionary->max_entries, sizeof(*dictionary->entries));
return dictionary;
}
void freeEntry(Entry *entry) {
free(entry->word);
free(entry->definition);
free(entry);
}
void freeDictionary(Dictionary *dictionary) {
for (--dictionary->num_entries; dictionary->num_entries >= 0; --dictionary->num_entries) {
// we can't call freeWord() here -- why.
free(dictionary->entries[dictionary->num_entries].word);
free(dictionary->entries[dictionary->num_entries].definition);
}
free(dictionary->entries);
free(dictionary);
}
void purgeInput() {
int c;
while ((c = getchar()) != '\n' && c != EOF) { }
}
Entry *requestNewEntry() {
Entry *entry = malloc(sizeof(*entry));
entry->word = malloc(MAX_WORD_LENGTH);
entry->definition = malloc(MAX_DEFINITION_LENGTH);
printf("============================\n");
printf("Enter word: ");
scanf("%[^\n]", entry->word);
purgeInput();
printf("\nEnter definition: ");
scanf("%[^\n]", entry->definition);
purgeInput();
return entry;
}
void addNewEntry(Entry *entry, Dictionary *dictionary) {
if (dictionary->num_entries == dictionary->max_entries) {
dictionary->max_entries *= 2;
dictionary->entries = realloc(dictionary->entries, dictionary->max_entries * sizeof(*dictionary->entries));
// check if realloc returns NULL and if so, handle the error.
}
dictionary->entries[dictionary->num_entries].word = strdup(entry->word);
dictionary->entries[dictionary->num_entries].definition = strdup(entry->definition);
dictionary->num_entries++;
}
int main() {
Dictionary *d = createNewDictionary();
for (int i = 0; i < 3; i++) {
Entry *e = requestNewEntry();
addNewEntry(e, d);
freeEntry(e);
}
printf("\nRead: ");
for (int i = 0; i < d->num_entries; i++) {
printf("%s (%lu chars) ", d->entries[i].word, strlen(d->entries[i].definition));
}
printf("\n");
freeDictionary(d);
return 0;
}
CREATING A PUN DICTIONARY
> ./a.out
============================
Enter word: silkworm
Enter definition: Two silkworms had a race but ended up in a tie.
============================
Enter word: horse
Enter definition: A horse is a stable animal.
============================
Enter word: termite
Enter definition: A termite walks into a pub and asks, "Is the bar tender here?"
Read: silkworm (47 chars) horse (27 chars) termite (62 chars)
>
I see what's wrong with your code. First of all, you need to pass your Dictionary object by pointer to the function, addNewWord, and in the function addNewWord, you again need to allocate memory to each of the char* fields, name and mean, of the dic object. Here is the corrected code :
void addNewWord(Words newword, Dictionary *dic){
dic->size++;
dic->word = (Words*)realloc(dic->word, dic->size*sizeof(Words));
dic->word[dic->size-1].name = (char*)malloc(30*sizeof(char)); //added
dic->word[dic->size-1].mean = (char*)malloc(30*sizeof(char)); //added
strcpy(dic->word[dic->size-1].name, newword.name);
strcpy(dic->word[dic->size-1].mean, newword.mean);
}
Pass the dictionary's address as :
addNewWord(createNewWord(), &d);
and change the definition as well as prototype of the function as well :
void addNewWord(Words newword, Dictionary *dic)
Find the complete code here : http://pastebin.com/ZN69hevj
I have a problem writing a code that should read usernames and put them in list. Every username should be connected to the number of times it has been entered. The problem occurs when entering the second username, my code places that username in the variable called first (where the first is kept). I guess I've done something wrong with the pointers, but I cannot find what. I am confused, in the end of one while loop the first one is the real first one, and when the program enters while again, variable first changes. How could that be? Please help me.
Thank you :)
typedef struct _user
{
char *name;
int counter;
struct _user *next;
} user;
int main() {
char userName [10];
int found = 0, go_on = 1;
user *first = NULL, *temp, *new;
while (go_on == 1) {
printf ("Username: ");
scanf("%s", userName);
if (first) {
// printf ("The first one in list: %s\n", first->name); - this prints the name of last username entered
for (temp = first; temp; temp = temp->next) {
if (strcmp (temp->name, userName) == 0) {
temp->counter++;
found = 1; }
if (found== 1) break;}
if (!found) {
new = (user*) malloc (sizeof(user));
new->name = userName;
new->counter = 1;
temp = new;
temp->next = NULL; } }
else {
new = (user*) malloc (sizeof(user));
new->name = userName;
new->counter = 1;
first = new;
first->next = NULL; }
printf ("Go on? (1/0)");
scanf("%d", &go_on);
printf ("Current list: ");
for (temp=first; temp; temp = temp->next)
printf("%s %d\n", temp->name, temp->counter);
//printf ("The first one in list: %s\n", first->name); - this prints the correct first
}
}
Your error, I think, is the userName array. You should allocate a new one for each element in your linked list. When you write new->name = userName;, you are not copying the name to the struct, you are making the struct point to your userName[10] array. As such every struct's actual "name" is storing only the single last name scanf-ed. That being said...
I generally prefer to write that kind of code with dedicated tools instead of logically embedding them in a loop construct:
Keeping your struct:
typedef struct _user
{
char *name;
int counter;
struct _user *next;
} user;
I would create a function that, given a properly constructed Sll returns a matching element:
function user *user_match_name(user *user_head, const ch *name)
{
user *cur_user = NULL;
/* look for a match */
for (cur_user = user_head ; cur_user ; cur_user = cur_user->next)
if(!strcmp(name,cur_user->name) return cur_user;
/* no match */
return NULL;
}
Then I usually prefer to have an Sll element builder:
function user *create_user(const ch *name)
{
user *new_user;
if(!(new_user = malloc(sizeof(user))))
printf("Error in allocation"); /* or better malloc error handling */
/* IMPORTANT: PROVIDE MEMORY FOR THE NAMES!!! */
if(!(new_user->name = malloc(sizeof(char)*256))) /* sizeof(char) is useless but I like to explicit it like that. And 256 should be enough a buffer could be better made */
printf("Error in allocation"); /* or better malloc error handling */
strncpy(new_user->name, name,256); /* not sure if I got the argument order right... */
new_user->counter = 0; /* or 1 depending on your prefered convention */
new_user->next = NULL;
return new_user;
}
It ease the debugging like you wouldn't believe! Then it's just a matter of rewriting your main function:
int main() {
char userName [10];
int found = 0, go_on = 1;
user *user_head = NULL, *new_user,*temp;
while (go_on == 1) {
printf ("Username: ");
scanf("%s", userName);
if( (new_user = user_match_name(user_head,userName)) )
++new_user->counter
else
new_user = create_user(userName);
/* Here we push on the Sll */
if(user_head){
new_user->next = user_head;
user_head = new_user;
} else {
user_head = new_user;
}
printf ("Go on? (1/0)");
scanf("%d", &go_on);
printf ("Current list: ");
for (temp = user_head; temp; temp = temp->next)
printf("%s %d\n", temp->name, temp->counter);
//printf ("The first one in list: %s\n", first->name); - this prints the correct first
}
}
Ahhhhhh! Much easier to read. Be mindful of: 1) I didn't compile check the code. The important ideas are there, leverage them. 2) Even in your previous implementation, you are white space vulnerable but that's somewhat another topic.
Or you could cimply fix it by doing:
typedef struct _user
{
char name[10];
int counter;
struct _user *next;
} user;
and strncpy(new->name,userName,10) instead of assigning the pointer.