I am making a linked list of objects. For some reason when i go to print the value of a value within the object (a char array) i'm getting junk printing before the value. Why is this happening and how do i get rid of it? Here is a part of my code:
int num = 0;
int input = 1;
int retval = 0;
struct PDB2 *llist;
char avalue[100] = "";
llist = (struct PDB2 *)malloc(sizeof(struct PDB2));
llist->data1[100] = NULL;
llist->next = NULL;
while(input != 0) {
printf("\n-- Menu Selection --\n");
printf("0) Quit\n");
printf("1) Insert\n");
printf("2) Delete\n");
printf("3) Search\n");
printf("4) Display\n");
scanf("%d", &input);
switch(input) {
case 0:
default:
printf("Goodbye ...\n");
input = 0;
break;
case 1:
printf("Your choice: `Insertion'\n");
printf("Enter the value which should be inserted: ");
scanf("%s", &avalue);
append_node(llist, avalue);
break;
case 2:
printf("Your choice: `Deletion'\n");
printf("Enter the value which should be deleted: ");
scanf("%s", &avalue);
delete_node(llist, avalue);
break;
case 3:
printf("Your choice: `Search'\n");
printf("Enter the value you want to find: ");
scanf("%s", &avalue);
if((retval = search_value(llist, avalue)) == -1)
printf("Value `%s' not found\n", avalue);
else
printf("Value `%s' located at position `%d'\n", avalue, retval);
break;
case 4:
printf("You choice: `Display'\n");
display_list(llist);
break;
} /* switch */
} /* while */
free(llist);
return(0);
}
void append_node(struct PDB2 *llist, char message[])
{
int x = 0;
while(llist->next != NULL)
{
llist = llist->next;
}
llist->next = (struct PDB2 *)malloc(sizeof(struct PDB2));
for(x = 0; x < 100; x++)
{
llist->next->data1[x] = message[x];
}
llist->next->next = NULL;
}
void display_list(struct PDB2 *llist)
{
while(llist->data1 == NULL)
{
llist = llist->next;
}
while(llist->next != NULL)
{
printf("%s ", llist->data1);
llist = llist->next;
}
printf("%s", llist->data1);
}
The char array in your initial node is uninitialized. Change
llist->data1[100] = NULL;
to
llist->data1[0] = '\0';
to stop it from being printed.
These two lines, together, are wrong:
char avalue[100] = "";
[...]
scanf("%s", &avalue);
The proper way to scanf a string is:
scanf("%s", avalue); // No Address-Of operator.
The important part of your code (based on your description of the problem) can be boiled down to this:
struct PDB2 {
char data[100];
...other fields...
};
struct PDB2 * llist = (struct PDB2 *)(malloc(sizeof(struct PDB2)));
llist->data[100] = NULL; /* This is wrong */
printf("%s", llist->data); /* This prints rubbish */
The marked line is wrong because:
NULL is meant to be used as a pointer value, not as a character. You probably mean to use '\0'.
The point seems to be to clear the string, so the correct method is
.
llist->data[0] = '\0';
Also, the call to scanf seems that it should be
char avalue[100];
scanf("%s", avalue);
since avalue is already of type char *. With the extra & you may be writing to an invalid location. However,
int input;
scanf("%d", &input);
is correct for integer input.
Related
I'm trying to write a function that deletes a node from a linked list. Each node corresponds to a person, which contains information such as an ID which is different for everyone, and to find the node to remove I ask the user the ID of the person he wants to remove, but the code as it is right now is not removing anything and I can't figure out why. Here's the function:
int rmv (int counter){
int id = 0;
int i = 0;
int opt = -1;
user_t* ptr = (user_t*)malloc(sizeof(user_t));
ptr = start;
printf ("ID to remove: ");
scanf ("%d", &id);
while (ptr != NULL){
if (ptr->id + 1 == id){
ptr = ptr->prox->prox;
printf ("Removed Successfully!\n");
}
else{
ptr = ptr->prox;
}
}
free (ptr);
while (opt < 0 || opt > 2){
printf ("*********************************************************");
printf ("\n-> 1-Go Back");
printf ("\n-> 2-Exit");
printf ("\n-> Option: ");
scanf ("%d", &opt);
}
switch (opt){
case 1: return (counter);
break;
case 2: exit (0);
}
}
I am creating an grocery store system as an assignment in C for a class I put off until my senior year. It uses a linked list to keep track of products in the store. I have gotten it mostly working, but for some reason each time I select a menu option, it will run until it tries to access a NULL memory location (Process finished with exit code -1073741819 (0xC0000005)) and exit with some random memory location that it tried to access instead of returning back to the main function.
I have tested out several different while loop conditionals, all of which lead to the process being terminated as it seems like NULL is accessed even if the conditional isn't met.
The program has two classes, both of which are below. I am trying to focus on the "showList" function for now, as I feel like if I'm able to figure one out, then I can correct the rest of them.
showList() is called by option 4 on the menu.
#include <stdio.h>
#include <stdlib.h>
#include "list.h"
void displayMenu()
{
puts("Welcome to the LinkedList grocery store.");
puts("Please let me know what you want to do by typing in one of the
numbers.");
puts("============================================================");
puts("1: Add product to store 2: Purchase product from store");
puts("3: Check price of a product 4: Show products in store");
puts("5: Remove a product from store 6: Find product");
puts("7: Inventory 8: Done for today");
}
int main(int argc, char *argv[])
{
product * head = NULL, *p;
char temp[N];
float sales = 0.0, quantity;
int choice, done = 0;
//system("cls");
head = load(head, "inventory.txt");
while (!done) {
displayMenu();
puts("What do you want to do?");
fflush(stdin);
scanf("%d", &choice);
fflush(stdin);
switch (choice)
{
case 1:
head = addProduct(head);
break;
case 2:
fflush(stdin);
printf("Please enter the name of a product: ");
fflush(stdin);
scanf("%s", temp);
fflush(stdin);
printf("Please enter the quantity: ");
fflush(stdin);
scanf("%f", &quantity);
fflush(stdin);
sales += purchase(head, temp, quantity);
break;
case 3:
fflush(stdin);
printf("Please enter the name of a product: ");
fflush(stdin);
scanf("%s", temp);
fflush(stdin);
checkPrice(head, temp);
break;
case 4:
showList(head);
break;
case 5:
fflush(stdin);
printf("Please enter the name of a product: ");
fflush(stdin);
scanf("%s", temp);
fflush(stdin);
rmItem(head, temp);
break;
case 6:
fflush(stdin);
printf("Please enter the name of a product: ");
fflush(stdin);
scanf("%s", temp);
fflush(stdin);
findProduct(head, temp);
break;
case 7:
puts("****INVENTORY****");
fflush(stdin);
printf("Total sales: %f\n", sales);
fflush(stdin);
display(head);
break;
case 8:
doneToday(head, "inventory.txt");
done = 1;
break;
default:
puts("Wrong code. Please try again.");
break;
}
}
return 0;
}
List.c:
#include "list.h"
// load in data from a file appending to the list l, return it
product * load(product *l, char fn[])
{
char name[N], quantity_unit[N], price_unit[N];
float quantity_value, price_value;
int rt;
product * head = l;
FILE * fin = fopen(fn, "r");
if(fin == NULL) {
printf("InLoad: File open failed (%s)\n", fn);
return NULL;
}
while (1) {
rt = fscanf(fin, "%s %f %s %f %s\n", name, &quantity_value,quantity_unit,
&price_value, price_unit );
if (rt < 5)
break;
if (head == NULL)
head = buildNode(name, quantity_value, quantity_unit, price_value,
price_unit);
else
append(head, buildNode(name, quantity_value, quantity_unit,
price_value, price_unit));
}
fclose(fin);
return head;
}
void doneToday(product* l, char fn[])
{
FILE * fout = fopen(fn, "w");
if(fout == NULL) {
printf("InSave: File open failed (%s)\n", fn);
return;
}
product* current = l;
while(current != NULL){
fprintf(fout, "%s %f %s %f %s\n", current->name, current-
>quantity_value,current->quantity_unit, current->price_value, current-
>price_unit);
current = current->next;
}
fclose(fout);
}
// build a product Node
product * buildNode(char name[], float quantity_value, char quantity_unit[],
float price_value, char price_unit[])
{
product * p = (product *) malloc(sizeof(product));
if(p == NULL) {
puts("InBuildNode: Memory Allocation Failed!");
return NULL;
}
strcpy(p->name, name);
p->quantity_value = quantity_value;
strcpy(p->quantity_unit, quantity_unit);
p-> price_value = price_value;
strcpy(p->price_unit, price_unit);
return p;
}
//shows the current product list
void showList(product *l)
{
product* cursor = l;
puts("************ Product List ******************");
printf("Name\tQuantity\tUnit\tPrice\t\tUnit\n\n");
while(cursor != NULL){
printf("%s\t%f\t%s\t%f\t%s\n", cursor->name, cursor->quantity_value,
cursor->quantity_unit, cursor->price_value, cursor->price_unit);
cursor = cursor->next;
}
}
//adds a product to the list if it's not already
product * addProduct(product* l)
{
product* cursor = l;
product* result = l;
char name[N];
float quantity_value;
char quantity_unit[N];
float price_value;
char price_unit[N];
puts("Please enter the name of a product: ");
scanf("%s", name);
puts("Please enter the quantity value of a product: ");
scanf("%f", &quantity_value);
puts("Please enter the quantity unit of a product: ");
scanf("%s", quantity_unit);
puts("Please enter the price value of a product: ");
scanf("%f", &price_value);
puts("Please enter the price unit of a product: ");
scanf("%s", price_unit);
while(cursor != NULL){
if(name == cursor->name){
cursor->quantity_value += quantity_value;
printf("The product with name **%s** already exists.", name);
printf("The quantity was updated. New quantity is: %f", cursor-
>quantity_value);
return result;
}
cursor = cursor->next;
}
if(!cursor){
result = append(l, buildNode(name, quantity_value, quantity_unit,
price_value, price_unit));
puts("New product added successfully!");
}
return result;
}
product * append(product *l, product * p)
{
product* cursor = l;
if(cursor == NULL){
return p;
} else {
while(cursor->next != NULL){
cursor = cursor->next;
}
cursor->next = p;
return l;
}
}
void checkPrice(product* l, char p[])
{
product* cursor = l;
while(cursor->next != NULL){
if(strcmp(cursor->name, p) == 0 ){
printf("The current price of %s is %f %s", p, cursor->price_value,
cursor->price_unit);
}
cursor = cursor->next;
}
}
void findProduct(product* l, char p[])
{
product* cursor = l;
while(cursor->next != NULL){
if(strcmp(cursor->name, p) == 0){
printf("Product Found: %s %f %s %f %s", cursor->name, cursor-
>quantity_value, cursor->quantity_unit, cursor->price_value, cursor-
>price_unit);
return;
}
cursor = cursor->next;
}
printf("The requested product was not found.");
}
void display(product *l)
{
product* cursor = l;
printf("Product: \n");
while(cursor){
printf("%s %f %s %f %s\n", cursor->name, cursor->quantity_value,
cursor->quantity_unit, cursor->price_value, cursor->price_unit);
cursor = cursor->next;
}
}
float purchase(product* l, char p[], float q){
product* cursor = l;
float dollars = 0.0;
while(cursor->next != NULL){
if(strcmp(cursor->name, p) == 0){
if(cursor->quantity_value > q){
dollars = cursor->price_value * q;
cursor->quantity_value -= q;
printf("Sale Completed, dollars made: %f\n", dollars);
return dollars;
} else if(cursor->quantity_value < q){
dollars = cursor->price_value * cursor->quantity_value;
printf("Sale partially completed, dollars made: %f\n", dollars);
rmItem(l, cursor);
return dollars;
}
}
}
printf("The sale was not completed, maybe the product doesn't exist.");
return dollars;
}
void rmItem(product* l, char p[])
{
product * current = l;
product * previous = current;
while(current != NULL) {
if (strcmp(current->name, p) == 0) {
if(previous == current) // the first node
l = (current->next);
else // not the first one
previous->next = current->next;
free (current);
return;
}
previous = current;
current = current->next;
}
}
list.h:
#ifndef PROJECT3_LIST_H
#define PROJECT3_LIST_H
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define N 20
struct product
{
char name[N];
float quantity_value;
char quantity_unit[N];
float price_value;
char price_unit[N];
struct product *next;
};
typedef struct product product;
product * load(product *l, char fn[]);
product * buildNode(char name[], float quantity_value, char quantity_unit[],
float price_value, char price_unit[]);
void showList(product *l);
product * addProduct(product* l);
product * append(product *l, product * p);
void checkPrice(product* l, char p[]);
void findProduct(product* l, char p[]);
void display(product *l);
float purchase(product* l, char product[], float q);
void rmItem(product* l, char p[]);
void doneToday(product* l, char fn[]);
#endif //PROJECT3_LIST_H
So i need to write and read to and from a binary file, but cant seem to do it, and when using readFromFile, the program crashes. I need help write to binary file, and then reading from it and resuming my work later after turning off the program.I have no idea what i am doing wrong, and i have googled for a long time now, but with no results. Here is the code of my program:
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
typedef struct{
char *subjName;
char *lectName;
char *lectSurname;
int credits;
int num_students;
}Subject;
typedef struct{
Subject **subjs;
int num_subjs;
}Subjects;
int numOfSubjs=0;
void listInput();
void listEdit();
void listDelete();
void listPrint();
int userChoice(int select);
int enterNumber(char *name);
void saveToFile(Subjects *subjects);
void readFromFile(Subjects *subjects);
int main() {
Subjects *subjects = malloc(sizeof(Subjects));
subjects->num_subjs = 0;
subjects->subjs = NULL;
readFromFile(subjects);
int r=1;
while(r!=0){
int select=userChoice(select);
switch(select){
case 1:
listPrint(subjects);
break;
case 2:
listInput(&subjects);
break;
case 3:
listDelete(subjects);
break;
case 4:
listEdit(subjects);
break;
case 0:
r=0;
break;
}
}
saveToFile(subjects);
return 0;
}
int userChoice(int select){ // menu options
int choice,input=0;
printf("(1). View all the data\n");
printf("(2). Enter new data\n");
printf("(3). Delete data\n");
printf("(4). Edit data\n");
printf("(0). Exit\n");
printf("-----------------------------\n");
while(input!=1){
choice = enterNumber("menu");
if(choice>4 || choice<0){
printf("Invalid input \n");
}
else
input = 1;
}
return choice;
}
void listPrint(Subjects *subjects){ // print data
int i;
for(i=0; i< numOfSubjs; i++){
printf("%d, %s, %s, %s, %d, %d\n",i+1, subjects->subjs[i]->subjName, subjects->subjs[i]->lectName, subjects->subjs[i]->lectSurname, subjects->subjs[i]->credits, subjects->subjs[i]->num_students);
}
printf("Number of entries: %d \n", numOfSubjs);
}
char *getln() //dynamically allocate input string
{
char *line = NULL, *tmp = NULL;
size_t size = 0, index = 0;
int ch = 1;
while (ch) {
ch = getc(stdin);
if (ch == '\n')
ch = 0;
if (size <= index) {
size += 1;
tmp = realloc(line, size);
if (!tmp) {
free(line);
line = NULL;
break;
}
line = tmp;
}
line[index++] = ch;
}
return line;
}
void saveToFile(Subjects *subjects){
FILE *data;
data = fopen("data.bin","wb");
printf("%s", subjects->subjs[0]);
for(int i=0; i<numOfSubjs; i++){
fwrite(&subjects->subjs[i],sizeof(Subject*),1,data);
}
fclose(data);
}
void readFromFile(Subjects *subjects){
FILE *data;
int i=0;
data = fopen("data.bin","rb");
while(!feof(data))
{
fread(&subjects->subjs[i],sizeof(Subject*),1,data);
i++;
}
fclose(data);
}
int isText(char *str,char *name){ // check if is text
for(int i = 0; i < strlen(str);i++){
if((str[i]<'A' || str[i]>'z') && str[i]!=' '){
printf("Error, %s must be a text \n",name);
return 0;
}
}
return 1;
}
int enterNumber(char *name){ // enter number and check if is number
int input=0, crash=0, num=0;
while(input!=1)
{
crash=0;
printf("Enter the number of %s\n", name);
scanf("%d", &num);
while(getchar()!='\n')
{
crash++;
}
if(crash>0 || num<0)
printf("Error, enter a not negative number of %s\n", name);
else if(crash==0)
input=1;
}
return num;
}
void listInput(Subjects **p_subjects){ // input new data
Subject *new_subj = malloc(sizeof(Subject));
new_subj->subjName = NULL;
new_subj->lectName = NULL;
new_subj->lectSurname = NULL;
new_subj->credits = 0;
new_subj->num_students = 0;
do{
printf("Enter the name of the subject \n");
new_subj->subjName = getln();
}while(!isText(new_subj->subjName,"Subject name"));
do{
printf("Enter the name of the lecturer \n");
new_subj->lectName = getln();
new_subj->lectName[0] &= '_';
}while(!isText(new_subj->lectName,"Lecturer's name"));
do{
printf("Enter the surname of the lecturer\n");
new_subj->lectSurname = getln();
new_subj->lectSurname[0] &= '_'; //Convert to uppercase if lowercase
}while(!isText(new_subj->lectSurname,"Lecturer's name"));
new_subj->credits = enterNumber("credits");
new_subj->num_students = enterNumber("students");
(*p_subjects)->subjs = realloc((*p_subjects)->subjs,sizeof(Subject*)*(++(*p_subjects)->num_subjs));
(*p_subjects)->subjs[(*p_subjects)->num_subjs-1] = new_subj;
numOfSubjs++;
printf("Added a new entry.\n\n");
}
void listDelete(Subjects *subjects){ // delete entries
int del;
if(numOfSubjs==0)
printf("Number of entries is 0, can't delete anything\n");
else{
printf("Enter 0 to exit. Number of subjects : %d \n", numOfSubjs);
while(1){
del = enterNumber("entry which you would like to delete");
if(del<=numOfSubjs && del>0){
for(int i = del-1; i<numOfSubjs-1; i++){
subjects->subjs[i]=subjects->subjs[i+1];
subjects->subjs = realloc(subjects->subjs,sizeof(Subject*)*(--subjects->num_subjs));
}
numOfSubjs--;
break;
}
if(del>numOfSubjs)
printf("Error, input a number between 1 and %d (or enter 0 to exit)\n", numOfSubjs);
else
break;
}
}
}
void listEdit(Subjects *subjects){ // edit entries
int choice=0, editEntry=0, editSubj=0;
if(numOfSubjs == 0)
printf("Number of entries is 0, can't edit anthing\n");
else{
while(1){
printf("Number of entry must be between 1 and %d \n", numOfSubjs);
choice = enterNumber("entry you would like to edit.");
if(choice>0 && choice<=numOfSubjs){
while(1){
editEntry = enterNumber("what would you like to edit\n 1 - Subject name\n 2 - Lecturer's name\n 3 - Lecturer's surname\n 4 - Number of credits\n 5 - Number of students");
if(editEntry>0 && editEntry <=5){
switch(editEntry){
case 1:
do{
printf("Enter the name of the subject \n");
subjects->subjs[choice-1]->subjName = getln();
}while(!isText(subjects->subjs[choice-1]->subjName,"Subject name"));
break;
case 2:
do{
printf("Enter Lecturer's name \n");
subjects->subjs[choice-1]->lectName = getln();
}while(!isText(subjects->subjs[choice-1]->lectName,"Lecturer's name"));
break;
case 3:
do{
printf("Enter Lecturer's surname \n");
subjects->subjs[choice-1]->lectSurname = getln();
}while(!isText(subjects->subjs[choice-1]->lectSurname,"Lecturer's surname"));
break;
case 4:
subjects->subjs[choice-1]->credits = enterNumber("credits");
break;
case 5:
subjects->subjs[choice-1]->num_students = enterNumber("students");
break;
}
}
break;
}
}
break;
}
}
}
&subjects->subjs[i], This is Undefined behavior. Accessing garbage value. You need to properly initialize it proper memory address. You ddin't do it anywhere.
(*subjects).subjs or subjects->subjs -> This is not pointing anywhere. It is NULL.
Also here you don't need the double pointer. A single pointer would do the thing you want to do.
typedef struct{
Subject *subjs;
int num_subjs;
}Subjects;
For single pointer this would be like
Subjects *subjects = malloc(sizeof(Subjects));
subjects->num_subjs = 10;
subjects->subjs = malloc(subjects->num_subjs * sizeof Subject);
subjects->subjs[0].subjName = malloc(40);
Each of the malloc should be checked with it's return Value. If it's NULL then it would be error to proceed further or access it.
And free() it accordingly when you are done working with it.
Some basic things:-
typedef struct{
Subject *subjs;
int num_subjs;
}Subjects;
Now let's look a bit in the code.
Op asked why OP should initialize and isn;t subjects->num_subjs = 0;
subjects->subjs = NULL; not enough?
A pointer is a variable that is supposed to hold address. here Subject* will hold the address of the variables of type Subject.
Now here initially you initialized it.
You have allocated a memory and assigned it's address to the Subject* variable subjects.
Now let's see what else you do.
subjects->num_subjs = 0;
subjects->subjs = NULL;
You initialized it. And then you try to access it(subjects->subjs[i]). Can you tell me where it points to? (subject->subjs)?
Answer is nope. It is pointing to nowhere. It contains NULL value now. Don't you think you should tell it how many subject you want to hold and allocate accordingly? Yes you should and that's what I did precisely in the example shown.
Whenever you have a pointer variable ask yourself what it contains - and if the value is something you know about, not some random garbage value.
I need your help with reading struct from binary file,
the "Grocery read_from_file ()..." function Can't get this to work!
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <ctype.h>
#include <conio.h>
struct grocerylist
{
int iD;
char grocery[30];
float amount;
char unit[10];
};
Grocery set_size_of(Grocery* list, int index);
Grocery input(int index);
void print_grocerylist(Grocery* list, int* index);
void write_to_file(FILE* file_pointer, Grocery* list, int index);
Grocery read_from_file(FILE* file_pointer, Grocery* list, int* index);
void change_item(Grocery* list, int index);
void remove_item(Grocery* list, int* index);
int main()
{
Grocery* list = (Grocery*)malloc(sizeof(Grocery)*1); //Grocery-array allocated memory for 1 struct
int index = 0, choice = 0;
FILE* file_pointer = NULL;
printf("Hey there user!\n");
while(choice != 7){
system("cls");
printf("Menu\n");
printf("1 - Add an item to the list.\n2 - Print the contents of your current list.\n3 - Print the contents to file.\n4 - Read from file.\n5 - Change an item on the list.\n6 - Remove item from the list.\n7 - close the program.\nChoose: ");
scanf("%d", &choice);
printf("\n");
switch(choice){
case 1:
list[index] = input(index);
index++;
*list = set_size_of(list, index); //Reallocating memory for the array of grocery-structs.
fflush(stdin);
break; //Add item
case 2:
print_grocerylist(list, &index); //Print list
fflush(stdin);
break;
case 3:
write_to_file(file_pointer, list, index); //print to file
fflush(stdin);
break;
case 4:
*list = read_from_file(file_pointer, list, &index); //read from file
fflush(stdin);
break;
case 5:
change_item(list, index); //change item
fflush(stdin);
break;
case 6:
remove_item(list, &index); //remove item
index--;
fflush(stdin);
break;
case 7:
free(list);
exit(EXIT_SUCCESS); //End program
break;
default:
printf("Wrong input, please try again!");
fflush(stdin);
getch();
break;
}
}
return 0;
}
Grocery set_size_of(Grocery* list, int index){ //reallocates memory.
list = realloc(list, (index+1)*sizeof(Grocery));
return *list;
}
Grocery input(index){
Grocery tmp;
int x = 0;
tmp.iD = index +1;
fflush(stdin);
printf("Grocery: ");
gets(tmp.grocery);
while(x == 0){
fflush(stdin);
printf("Amount: ");
x = scanf("%f", &tmp.amount);
if(x == 0){
puts("Error, please try again!");
}
}
fflush(stdin);
x = 0;
while(x == 0){
printf("Unit: ");
gets(tmp.unit);
if(isalpha(*tmp.unit)){
x = 1;
}else{
x = 0;
puts("Error: please try again!\n");
}
}
printf("\n");
return tmp;
}
void print_grocerylist(Grocery* list, int* index){
int i;
system("cls");
printf("The grocery list contains:\n");
printf("Item Amount Unit");
for(i=0;i<*index;i++)
{
printf("\n%d: %-10s %5.1f %6s", list[i].iD, list[i].grocery, list[i].amount, list[i].unit);
}
printf("\n");
getch();
printf("Press any key to continue.\n");
}
void write_to_file(FILE* file_pointer, Grocery* list, int index){ //works just fine afaik.. Prints the index at the start, fills it up with all the rest.
char filename[30];
memset(filename, '\0', sizeof(filename));
printf("What is the name of the file you wish to write to?: ");
scanf("%s", filename);
strcat(filename, ".txt");
file_pointer = fopen(filename, "wb");
if(file_pointer == NULL){
printf("Error!");
return;
}else{
fflush(stdin);
printf("File opened successfully!\n");
fwrite(&index, sizeof(int), 1, file_pointer);
fwrite(list, sizeof(Grocery), index, file_pointer);
printf("File written.");
getch();
}
fclose(file_pointer);
return;
}
Grocery read_from_file(FILE* file_pointer, Grocery* list, int* index){ //Can't get this to work...
char filename[30];
memset(filename, '\0', sizeof(filename));
printf("What is the name of the file you wish to read from?: ");
scanf("%s", filename);
strcat(filename, ".txt");
file_pointer = fopen(filename, "rb");
if(file_pointer == NULL){
printf("Error!");
return *list;
}else{
fflush(stdin);
free(list);
printf("File opened successfully!\n");
fread(index, sizeof(int), 1, file_pointer);
printf("Index %d read.\n", *index);
list = (Grocery*)calloc(*index, sizeof(Grocery));
fread(list, sizeof(Grocery), (*index), file_pointer);
printf("File read.");
getch();
fflush(stdin);
}
fclose(file_pointer);
return *list;
}
void change_item(Grocery* list, int index){ //Basically it's a more complex version of "Grocery input()" were we look to the ID/index and alter the information.
int x = 0, id, item, choice;
print_grocerylist(list, &index);
printf("Which item would you like to change?\nID number: ");
scanf("%d", &id);
printf("\nWhat do you want to change?\n1 - Grocery.\n2 - Amount.\n3 - Unit.\nChoose: ");
scanf("%d", &choice);
switch(choice){
case 1:
fflush(stdin);
printf("Grocery: ");
for(item = 0; item <= index; item++){
if(list[item].iD == id){
gets(list[item].grocery);
}
}
break;
case 2:
while(x == 0){
fflush(stdin);
printf("Amount: ");
for(item = 0; item <= index; item++){
if(list[item].iD == id){
x = scanf("%f", &list[item].amount);
}
}
if(x == 0){
puts("Error, please try again!");
}
}
break;
case 3:
fflush(stdin);
x = 0;
printf("Unit: ");
for(item = 0; item <= index; item++){
if(list[item].iD == id){
gets(list[item].unit);
if(isalpha(*list[item-1].unit)){
x = 1;
}else{
x = 0;
puts("Error: please try again!\n");
}
}
}
break;
default:
printf("\nError! Please try again.\n");
break;
}
return;
}
void remove_item(Grocery* list, int* index){ //Takes the last struct and copies it to the slot which will be "removed" and then reallocates the memory for the array -1, keeping the old ID, to make things simple.
int item;
printf("Which item would you like to remove?\nID number: ");
scanf("%d", &item);
strcpy(list[item].grocery, list[*index].grocery);
list[item].amount = list[*index].amount;
strcpy(list[item].unit, list[*index].unit);
list = realloc(list, (*index-1)*sizeof(Grocery));
return ;
}
For the most part, the "Grocery read_from_file()" function works, but it returns only the first item instead of the list it correctly read.
To return and assign (a pointer to) the whole list, change the call
*list = read_from_file(file_pointer, list, &index);
to
list = read_from_file(file_pointer, list, &index);
and the definition
Grocery read_from_file(FILE* file_pointer, Grocery* list, int* index){
…
return *list;
…
return *list;
}
to
Grocery *read_from_file(FILE *file_pointer, Grocery *list, int *index)
{
…
return list;
…
return list;
}
To not leak the memory of the old list when it reads one from a file, insert free(list) before list = (Grocery*)calloc(*index, sizeof(Grocery)); or change that to
list = realloc(list, *index * sizeof(Grocery));
it is the all day that I edit my code, but can't find the reason why the last position of my array get overwritten!!
#include <stdio.h>
#include <math.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
typedef struct Person{
char *name;
char *surname;
char *address;
char *number;
} Person;
char * getString(void);
int main(void) {
struct Person *rub = NULL, *ttmp = NULL;
int idx=0,i,j,k;
char c;
char *tmp = NULL;
do{
printf("*******************************\ni - Insert new\n");
printf("n - Find by name\n");
printf("c - Find by surname\n");
printf("e - Delete\n");
printf("p - Print list\n");
printf("0 - Exit\n*******************************\n");
c = getchar();
printf("%d\n",c);
getchar();
switch(c){
case 'i':
ttmp = (struct Person *) realloc(rub, (idx+1)*sizeof(Person));
if(ttmp == NULL){
printf("Cannot allocate more memory.\n");
exit(1);
}
else
rub = ttmp;
printf("Nome: ");
tmp = getString();
rub[idx].name = (char *) malloc(strlen(tmp));
rub[idx].name = tmp;
//printf("Surname: "); //commented in order to test faster
//tmp = getString();
rub[idx].surname = (char *) malloc(strlen(tmp));
rub[idx].surname = tmp;
//printf("Address: ");
//tmp = getString();
rub[idx].address = (char *) malloc(strlen(tmp));
rub[idx].address = tmp;
//printf("Number: ");
//tmp = getString();
rub[idx].number = (char *) malloc(strlen(tmp));
rub[idx].number = tmp;
idx++;
for(k=0;k<idx;k++){
printf("%d) %s %s\n%s\n%s\n-------------------\n", k+1, rub[k].name,rub[k].surname,rub[k].address,rub[k].number);
}
break;
case 'n':
printf("What name are you looking for? ");
scanf("%s",tmp);
for(k=0;k<idx;k++){
if(strcmp(rub[k].name,tmp) == 0){
printf("%s\n%s\n%s\n%s\n", rub[k].name,rub[k].surname,rub[k].address,rub[k].number);
}
}
break;
case 'c':
printf("What surname are you looking for? ");
scanf("%s",tmp);
for(k=0;k<idx;k++){
if(strcmp(rub[k].surname,tmp) == 0){
printf("%s\n%s\n%s\n%s\n", rub[k].name,rub[k].surname,rub[k].address,rub[k].number);
}
}
break;
case 'e':
printf("Select number to delete record:\n ");
for(k=0;k<idx;k++){
printf("%d) %s %s\n", k+1, rub[k].name,rub[k].surname);
}
scanf("%d",&j);
ttmp = NULL;
for(k=0,i=0;k<idx;k++){
if(k+1 != j){
ttmp = (struct Person *) realloc(ttmp, (i+1)*sizeof(Person));
ttmp[i].name = (char *) malloc(strlen(rub[k].name));
ttmp[i].surname = (char *) malloc(strlen(rub[k].surname));
ttmp[i].address = (char *) malloc(strlen(rub[k].address));
ttmp[i].number = (char *) malloc(strlen(rub[k].number));
ttmp[i].name = rub[k].name;
ttmp[i].surname = rub[k].surname;
ttmp[i].address = rub[k].address;
ttmp[i].number = rub[k].number;
i++;
}
}
--idx;
rub = (struct Person *) realloc(ttmp, (idx)*sizeof(Person));
for(k=0;k<idx;k++){
printf("%d/%d) %s %s\n%s\n%s\n-------------------\n", k,idx, rub[k].name,rub[k].surname,rub[k].address,rub[k].number);
}
break;
case 'p':
for(k=0;k<idx;k++){
printf("%d) %s %s\n%s\n%s\n-------------------\n", k+1, rub[k].name,rub[k].surname,rub[k].address,rub[k].number);
}
break;
case '0':
return 0;
break;
}
fseek(stdin,0,SEEK_END);
}
while(c != 0);
return 0;
}
char * getString(void){
char *stringa = NULL, c;
int i=0;
stringa = malloc(sizeof(char));
while((c=getchar()) != '\n'){
stringa = (char *) realloc(stringa, (i+1)*sizeof(char));
stringa[i++] = c;
}
stringa[i] = '\0';
return stringa;
}
Here is my input (please enter the same input, and tell me if you get the same error). I will use some stupid and random words for this example:
i
asd
i
qwe
i
zxc
p
n
asd
p
Here is the output of my last 'p' command:
1) asd asd
asd
asd
-------------------
2) qwe qwe
qwe
qwe
-------------------
3) asd asd
asd
asd
-------------------
Why the last position of the array became the same as the first??
Any other advice or suggestion for the code will be welcome!!
thanks
Why the last position of the array became the same as the first?
case 'n':
printf("What name are you looking for? ");
scanf("%s",tmp);
tmp are reused. (case 'c': too)
change to
E.g
case 'n':
printf("What name are you looking for? ");
tmp=getString();
for(k=0;k<idx;k++){
if(strcmp(rub[k].name,tmp) == 0){
printf("%s\n%s\n%s\n%s\n", rub[k].name,rub[k].surname,rub[k].address,rub[k].number);
}
}
free(tmp);
break;
and
rub[idx].name = (char *) malloc(strlen(tmp));
rub[idx].name = tmp;
//As well as in other like
memory leak.
only
rub[idx].name = tmp;//by getString()
I din't read the whole code but found this code that seems incorrect:
stringa = malloc(sizeof(char));
while((c=getchar()) != '\n'){
stringa = (char *) realloc(stringa, sizeof(char));
You are realloc-ing always one byte, the string nevers grows up!
You should realloc depending on the variable i