I am trying to create a program that implements a basic character sheet with an inventory. User
will be able to create a character, view their info, add items, and view items.
There are functions for each functionality.
I created a header file charactersheet.h to define structure and function inside it.
#include <stdio.h>
struct Item {
char *name;
int price;
double weight;
};
struct Inventory {
struct Item **item;
int numitems;
};
struct Character {
char *name;
int Level;
long XP;
struct Inventory inventory;
};
void
createCharacter(struct Character *c)
{
printf("Enter Name:");
c->name = (char *) malloc(40 * sizeof(char));
scanf("%s", c->name);
printf("Enter Level:");
scanf("%d", &c->Level);
printf("Enter XP:");
scanf("%ld", &c->XP);
}
void
viewCharacter(struct Character *b)
{
printf("%s level %d with %ld XP", b->name, b->Level, b->XP);
}
void
addItem(struct Inventory *i)
{
i->numitems = i->numitems + 1;
printf("Enter name:");
scanf("%s", i->item[i->numitems]->name);
printf("Enter price:");
scanf("%d", &(i->item[i->numitems]->price));
printf("Enter Weight:");
scanf("%d", &(i->item[i->numitems]->weight));
}
void
viewItem(struct Inventory i)
{
for (int j = 0; j < i.numitems; j++)
printf("%s,%d golds,%.2lf pounds", i.item[j]->name, i.item[j]->price, i.item[j]->weight);
}
The addItem function takes Inventory * function as input reallocate the memory to accommodate the additional item.
The viewItem function takes Inventory as parameter and list all items.
Now in the file charactersheet.c I have following implementation
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "charsheet.h"
int
main(void)
{
struct Item items;
struct Inventory inventory;
struct Character chars;
inventory.numitems = 0;
while (1) {
char choice;
printf("\nC Create character\n");
printf("V view Character\n");
printf("A Add Item\n");
printf("I view Items\n");
printf("Q Quit\n");
scanf(" %c", &choice);
switch (choice) {
case 'C':
createCharacter(&chars);
break;
case 'V':
viewCharacter(&chars);
break;
case 'A':
addItem(&inventory);
break;
case 'I':
viewItem(inventory);
break;
case 'Q':
exit(0);
default:
printf("Invalid input\n");
}
}
return 0;
}
However I am not able to implement addItem and viewItem functions. There are no errors in the code in my editor as well.
There were a number of issues.
In the Inventory struct, you [proably] want *item instead of **item. The double pointer made things needlessly complicated.
In addItem, you need to do a realloc on item to increase the length of the array before trying to fill in the data.
If we still had the **item, this would have required an additional malloc for each new struct.
In addItem, you were doing a scanf for name, but were not allocating it, so that was UB. Better to do the scanf on a fixed buffer and then use strdup.
In createCharacter, you're doing a fixed malloc of length 40. Better to use a [large] fixed size buffer and then do strdup
In viewItem, you were passing the struct by value. While that's legal, most of the time, you want to pass a pointer to the struct instead.
Here's some refactored code. I used preprocessor conditionals to show your/old vs. my/new code:
#if 0
// old code
#else
// new code
#endif
Anyway, here is the .h file:
#include <stdio.h>
struct Item {
char *name;
int price;
double weight;
};
struct Inventory {
#if 0
struct Item **item;
#else
struct Item *item;
#endif
int numitems;
};
struct Character {
char *name;
int Level;
long XP;
struct Inventory inventory;
};
Here is the .c file. As per my top comments, I moved the function bodies here:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "charsheet.h"
void
createCharacter(struct Character *c)
{
printf("Enter Name:");
#if 0
c->name = (char *) malloc(40 * sizeof(char));
scanf("%s", c->name);
#else
char buf[1000];
scanf("%s",buf);
c->name = strdup(buf);
#endif
printf("Enter Level:");
scanf("%d", &c->Level);
printf("Enter XP:");
scanf("%ld", &c->XP);
}
void
viewCharacter(struct Character *b)
{
printf("%s level %d with %ld XP\n", b->name, b->Level, b->XP);
}
void
addItem(struct Inventory *i)
{
i->numitems = i->numitems + 1;
#if 0
printf("Enter name:");
scanf("%s", i->item[i->numitems]->name);
printf("Enter price:");
scanf("%d", &(i->item[i->numitems]->price));
printf("Enter Weight:");
scanf("%d", &(i->item[i->numitems]->weight));
#else
struct Item *t;
t = realloc(i->item,sizeof(*t) * i->numitems);
if (t == NULL) {
perror("item");
exit(1);
}
i->item = t;
t += i->numitems - 1;
char buf[1000];
printf("Enter name:");
scanf("%s", buf);
t->name = strdup(buf);
printf("Enter price:");
scanf("%d", &t->price);
printf("Enter Weight:");
scanf("%d", &t->weight);
#endif
}
#if 0
void
viewItem(struct Inventory i)
#else
void
viewItem(struct Inventory *i)
#endif
{
for (int j = 0; j < i->numitems; j++) {
struct Item *t = &i->item[j];
printf("%s,%d golds,%.2lf pounds\n",
t->name, t->price, t->weight);
}
}
int
main(void)
{
struct Item items;
struct Inventory inventory;
struct Character chars;
inventory.numitems = 0;
#if 1
inventory.item = NULL;
#endif
#if 1
setbuf(stdout,NULL);
#endif
while (1) {
char choice;
printf("\nC Create character\n");
printf("V view Character\n");
printf("A Add Item\n");
printf("I view Items\n");
printf("Q Quit\n");
scanf(" %c", &choice);
switch (choice) {
case 'C':
createCharacter(&chars);
break;
case 'V':
viewCharacter(&chars);
break;
case 'A':
addItem(&inventory);
break;
case 'I':
#if 0
viewItem(inventory);
#else
viewItem(&inventory);
#endif
break;
case 'Q':
exit(0);
break;
default:
printf("Invalid input\n");
break;
}
}
return 0;
}
UPDATE:
what if i need **item?
Well, I think you should have some justification for the extra complexity. But, if it's a requirement, it is possible.
Also, the scanf for weight was using the wrong format. If you had enabled warnings by compiling with -Wall [which you should always do], the compiler would have flagged this for you.
Here's the code with code for double pointers. Note that I've merged the .h into the .c here for brevity:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifndef DOUBLE_POINTER
#define DOUBLE_POINTER 0
#endif
struct Item {
char *name;
int price;
double weight;
};
struct Inventory {
#if DOUBLE_POINTER
struct Item **item;
#else
struct Item *item;
#endif
int numitems;
};
struct Character {
char *name;
int Level;
long XP;
struct Inventory inventory;
};
void
createCharacter(struct Character *c)
{
printf("Enter Name:");
#if 0
c->name = (char *) malloc(40 * sizeof(char));
scanf("%s", c->name);
#else
char buf[1000];
scanf("%s",buf);
c->name = strdup(buf);
#endif
printf("Enter Level:");
scanf("%d", &c->Level);
printf("Enter XP:");
scanf("%ld", &c->XP);
}
void
viewCharacter(struct Character *b)
{
printf("%s level %d with %ld XP\n", b->name, b->Level, b->XP);
}
void
addItem(struct Inventory *i)
{
i->numitems = i->numitems + 1;
#if 0
printf("Enter name:");
scanf("%s", i->item[i->numitems]->name);
printf("Enter price:");
scanf("%d", &(i->item[i->numitems]->price));
printf("Enter Weight:");
scanf("%d", &(i->item[i->numitems]->weight));
#else
struct Item *t;
i->item = realloc(i->item,sizeof(*i->item) * i->numitems);
if (i->item == NULL) {
perror("item");
exit(1);
}
#if DOUBLE_POINTER
t = malloc(sizeof(*t));
i->item[i->numitems - 1] = t;
#else
t = &i->item[i->numitems - 1];
#endif
char buf[1000];
printf("Enter name:");
scanf("%s", buf);
t->name = strdup(buf);
printf("Enter price:");
scanf("%d", &t->price);
printf("Enter Weight:");
#if 0
scanf("%d", &t->weight);
#else
scanf("%lf", &t->weight);
#endif
#endif
}
#if 0
void
viewItem(struct Inventory i)
#else
void
viewItem(struct Inventory *i)
#endif
{
for (int j = 0; j < i->numitems; j++) {
#if DOUBLE_POINTER
struct Item *t = i->item[j];
#else
struct Item *t = &i->item[j];
#endif
printf("%s,%d golds,%.2lf pounds\n",
t->name, t->price, t->weight);
}
}
int
main(void)
{
#if 0
struct Item items;
#endif
struct Inventory inventory;
struct Character chars;
inventory.numitems = 0;
#if 1
inventory.item = NULL;
#endif
#if 1
setbuf(stdout,NULL);
#endif
while (1) {
char choice;
printf("\nC Create character\n");
printf("V view Character\n");
printf("A Add Item\n");
printf("I view Items\n");
printf("Q Quit\n");
scanf(" %c", &choice);
switch (choice) {
case 'C':
createCharacter(&chars);
break;
case 'V':
viewCharacter(&chars);
break;
case 'A':
addItem(&inventory);
break;
case 'I':
#if 0
viewItem(inventory);
#else
viewItem(&inventory);
#endif
break;
case 'Q':
exit(0);
break;
default:
printf("Invalid input\n");
break;
}
}
return 0;
}
The addItem function takes Inventory * function as input reallocate the memory to accommodate the additional item
Well, it could but it does not
void addItem(struct Inventory* i){
i->numitems =i->numitems + 1;
printf("Enter name:");
scanf("%s",i->item[i->numitems]->name);
printf("Enter price:");
scanf("%d",&(i->item[i->numitems]->price));
printf("Enter Weight:");
scanf("%d",&(i->item[i->numitems]->weight));
}
Inventory is a struct, an array of numitems pointers to item
You need to build it carefully. They would not come to life just by adding 1 to a counter.
Some things you may consider
As pointed already in the comments, INDENT your code
Use typedef to name your structs
Use a convention to struct naming, like first letter in uppercase only for structs
When you declare Item **item; you are declaring item, so write Item** item instead. This way makes clear what is what and no one needs to search for asterisks around names in declarations. item is Item**, *item is Item* and **item points to the first Item.
do not return void. In general is a waste of something, maybe an error
use menu() as a function to return the user option
do not use scanf(): it has another purpose: scan formatted input. But when you use always test the return. scanf() return an int. Read the manual.
do not put code or declare variables in a header: use another file with the same name as your header and put your code there
leave main() in another file so you can have many test programs to test your set of functions...
do not mix logic and data entry in the same function: it creates a bad dependency and limits your testing capabilities.
also see things like this
void addItem(Inventory*);
addItem() adds an item to an inventory. Write
int addItem( item Item*, Inventory* inv);
And maybe return 0 for ok or an error code, but pass pointers to Item and Inventory. It is clearer and more manageable...
maybe you need another Inventory, a dynamic array of Character
A possible header
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct
{
char* name;
int price;
double weight;
} Item;
typedef struct
{
Item** item;
int size;
} Inventory;
typedef struct
{
Inventory inventory;
int level;
char* name;
long xp;
} Character;
typedef struct
{
Character** item;
int limit;
int size;
} Cast;
int addItem(Item*, Inventory*);
Cast* buildCast(unsigned);
Character* createCharacter(Character*);
int viewCharacter(Character*);
int viewItem(Inventory*);
Using typedef to the structs, a convention that first letter in uppercase means a struct name, and a Cast struct to hold the Character set.
I am adding a buildCast() that shows the usual way to build this sort of thing, the same thing the system does for every program building argc and argv as
int main( int argc, char** argv)
typedef struct
{
Character** item;
int limit;
int size;
} Cast;
You can write
Cast* buildCast(unsigned count)
{
// builds an array of 'count' pointers
// to 'Character'
if( count == 0 ) return NULL;
Cast* one = (Cast*) malloc(sizeof(Cast));
one->limit = count;
one->size= 0; // empty
one->item = (Character**) malloc( count * sizeof(Character*));
for( int i =0; i<count; i+= 1)
one->item[i] = NULL;
return one;
}
And call as in
Cast* cast = buildCast(300);
To have an array of 300-max pointers to Character initially empty
This is just an example using your code and has errors as I did not correct the issues on memory allocation, for example.
You can look at buildCast() and see how to build your inventory struct.
I will left a set of files here that you can compile and run and move on if you decided to go this way. It is just your code refactored.
1 of 3 soch.h header:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct
{
char* name;
int price;
double weight;
} Item;
typedef struct
{
Item** item;
int size;
} Inventory;
typedef struct
{
Inventory inventory;
int level;
char* name;
long xp;
} Character;
typedef struct
{
Character** item;
int limit;
int size;
} Cast;
int addItem(Item*, Inventory*);
Cast* buildCast(unsigned);
Character* createCharacter(Character*);
char menu();
int viewCharacter(Character*);
int viewItem(Inventory*);
2 of 3 sohc.c functions
#include"soch.h"
int addItem(Item* it, Inventory* inv)
{
printf("Enter name:");
scanf("%s",it->name);
printf("Enter price:");
scanf("%d",&(it->price));
printf("Enter Weight:");
scanf("%lf",&(it->weight));
inv->item[inv->size] = it;
inv->size =inv->size + 1;
return 0;
}
Cast* buildCast(unsigned count)
{
// builds an array of 'count' pointers
// to 'Character'
if( count == 0 ) return NULL;
Cast* one = (Cast*) malloc(sizeof(Cast));
one->limit = count;
one->size= 0; // empty
one->item = (Character**) malloc( count * sizeof(Character*));
for( int i =0; i<count; i+= 1)
one->item[i] = NULL;
return one;
}
Character* createCharacter(Character* c)
{
Character* one = NULL;
printf("Enter Name:");
c->name = (char*) malloc(40*sizeof(char));
scanf("%s",c->name);
printf("Enter Level:");
scanf("%d",&c->level);
printf("Enter XP:");
scanf("%ld",&c->xp);
return one;
}
char menu()
{
char choice[30];
printf("\nC Create character\n");
printf("V view Character\n");
printf("A Add Item\n");
printf("I view Items\n");
printf("Q Quit\n");
fgets( choice, sizeof(choice), stdin);
return choice[0];
};
int viewCharacter(Character* b)
{
printf("%s level %d with %ld XP",
b->name,
b->level,
b->xp);
return 0;
}
int viewItem(Inventory* i)
{
for(int j=0; j<i->size; j++)
{
printf(
"%s,%d golds,%.2lf pounds\n",
i->item[j]->name,
i->item[j]->price,
i->item[j]->weight);
};
return 0;
}
main function to test buildCast() and menu()
#include "soch.h"
int main(void)
{
Inventory inventory;
Item item;
Character chars;
Cast* cast = buildCast(300);
while(1)
{
switch(menu())
{
case 'C':
createCharacter(&chars);
break;
case 'V':
viewCharacter(&chars);
break;
case 'A':
addItem(&item, &inventory);
break;
case'I':
viewItem(&inventory);
break;
case 'Q':
exit(0);
default:
printf("Invalid input\n");
break;
}; // switch()
}; // while()
return 0;
};
In practice you would build structs like Inventory in blocks of N pointers, for efficiency, and if needed call realloc() when more pointers are needed. But for a simple program you can write a fixed array of pointers or malloc() one by one and see how it goes.
Write back if you choose to go this way. Take a look at the provided code
Related
I'm having a problem to allocate a structure dynamically.
I'm making a program that works as a contact book, but I'm getting the
following error: Segmentation fault (core dumped).
The structure declaration, following the functions to add a contact
and print all contacts:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct contact{
int number;
char name[80];
}contact;
void addContact(contact **contacts, int position){
int aux=position;
printf("Enter the name: ");
setbuf(stdin, 0);
fgets(contacts[position]->name,80,stdin);
printf("Enter the telephone number: ");
scanf("%d",&contacts[position]->number);
return;
}
void printAllContacts(contact **contacts, int size){
for(int i;i<size;i++){
printf("Contact %d:\n",i);
printf("Name: %s\n",contacts[i]->name);
printf("Telephone number: %d \n",contacts[i]->number);
}
}
// Main function:
int main(){
int size;
printf("Enter the list size: ");
scanf("%d",&size);
contact *contacts= (contact*)malloc(sizeof(contact)*size);
int counter=0;
int x;
do{
printf("------------MENU-----------\n");
printf("1-Add contact\n");
printf("2-Print contacts list\n");
printf("0-Exit\n");
printf("----------------------------\n");
printf("Enter an option: ");
scanf("%d",&x);
switch (x){
case 1:
addContact(&contacts,counter);
counter++;
break;
case 2:
printAllContacts(&contacts,counter);
break;
case 0:
break;
}
}while(x!=0);
return 0;
}
Can anyone help?
The basic problem is that you're allocating an array of struct contact objects, but your addContact and printAllContacts expect an array of pointers to struct contact. You need to choose one or the other.
The easiest fix is probably to change the functions -- change the argument type to contact * instead of contact **, remove the & at the call site in main, and change the -> to . in the functions where needed.
Pass in a pointer (contacts *) instead of pointer to pointer (contacts **) to addContact() & printAllContacts(). Updated caller, and partially updated called code which already assumed it was operating on an array.
Initialize i in printAllContacts().
Removed the unnecessary cast of malloc() return value.
Removed the name of the struct as you use only use the typedef.
Introduced a NAME_LEN macro instead of the magic 80 value.
Minor reformatting for readability & consistency.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NAME_LEN 80
typedef struct {
int number;
char name[NAME_LEN];
} contact;
void addContact(contact *contacts, int position) {
printf("Enter the name: ");
setbuf(stdin, 0);
fgets(contacts[position].name, NAME_LEN, stdin);
printf("Enter the telephone number: ");
scanf("%d", &contacts[position].number);
return;
}
void printAllContacts(contact *contacts, int size) {
for(int i=0; i<size;i++) {
printf("Contact %d:\n", i);
printf("Name: %s\n", contacts[i].name);
printf("Telephone number: %d\n", contacts[i].number);
}
}
int main() {
int size;
printf("Enter the list size: ");
scanf("%d", &size);
contact *contacts = malloc(sizeof(contact)*size);
int counter=0;
int x;
do {
printf("------------MENU-----------\n");
printf("1-Add contact\n");
printf("2-Print contacts list\n");
printf("0-Exit\n");
printf("----------------------------\n");
printf("Enter an option: ");
scanf("%d", &x);
switch (x) {
case 1:
addContact(contacts, counter++);
break;
case 2:
printAllContacts(contacts, counter);
break;
case 0:
break;
}
} while(x!=0);
return 0;
}
I would add additional structure holding all the contacts and also keeping the number of contacts stored. You do not need to know the size of the list - it will grow with any added contact.
When you test the idea I would advise you to not use user input functions, only fixed data. It makes debugging and testing faster and easier. Especially function which adds data should not communicate with the external world. Caller is the correct place to do it
Also use function return values to return result or status codes. You tend to use void everywhere - it is not a good idea.
typedef struct contact{
unsigned number;
char name[80];
}contact;
typedef struct
{
size_t size;
contact contacts[];
}constactList;
constactList *addContact(constactList *list, const char *name, const unsigned number)
{
size_t newsize = list ? list -> size + 1 : 1;
list = realloc(list, sizeof(*list) + sizeof(list -> contacts[0]) * newsize);
if(list)
{
strncpy(list -> contacts[list -> size].name, name, sizeof(list -> contacts[0].name));
list -> contacts[list -> size].name[sizeof(list -> contacts[0].name) - 1] = 0;
list -> contacts[list -> size].number = number;
list -> size = newsize;
}
return list;
}
void printContacts(const constactList *list)
{
if(list)
{
for(size_t i = 0; i < list -> size; i++) printf("[%3zu] %s, %u\n", i, list -> contacts[i].name, list -> contacts[i].number);
}
}
int main(void)
{
constactList *list = NULL;
list = addContact(list, "James Bond", 7);
if(!list) {/* error handling*/}
list = addContact(list, "Mata Hari", 99);
if(!list) {/* error handling*/}
list = addContact(list, "Wladymir Putin", 666);
if(!list) {/* error handling*/}
printContacts(list);
free(list);
}
This code has several issues that are beyond my understanding.
First, no matter how hard I try, the variable ok doesn't get saved in the file, thus ruining the display. It is strange because other variables work, it is just that one that doesn't seem to be working, even if I change the order.
Also, the delete and modify functions aren't working, as well.
I tried everything, but nothing seems to be working.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
// Structure of the employee
struct emp {
char name[50];
char ok[50];
int hr;
int age;
int id;
};
FILE *f;
emp* add(emp *e,int n){
int i;
char p;
emp *t;
int k;
t=(emp*)malloc(n*sizeof(int));
f=fopen("Data.txt","w");
for(i=0;i<n;i++){
printf("\nEnter Name : ");
scanf("%s",(t+i)->name);
printf("\nEnter Departement: ");
scanf("%s",&(t+i)->ok);
printf("\nEnter Age : ");
scanf("%d",&(t+i)->age);
printf("\nEnter avearge hour of works(per week) : ");
scanf("%d",&(t+i)->hr);
// k = ( ( (t+i)->hr ) *40 );//40 is minimum wage for each hour of work
// printf("Salary of The employe: %d\n",k);
printf("\nEnter EMP-ID : ");
scanf("%d",&(t+i)->id);
fprintf(f,"%s\n%s\n%d\n%d\n%d\n",(t+i)->name,(t+i)->ok,(t+i)->age,(t+i)->hr,(t+i)->id);
}
fclose(f);
return t;
}
void aff(emp *t,int n){
int I;
f=fopen("Data.txt","r");
for(i=0;i<n;i++){
if (f != NULL){
fscanf(f,"%s",&(t+i)->name);
fscanf(f,"%s",&(t+i)->ok);
fscanf(f,"%d",&(t+i)->age);
fscanf(f,"%d",&(t+i)->hr);
fscanf(f,"%d",&(t+i)->id);
printf("Name : %s\n",(t+i)->name);
printf("departement : %s\n",(t+i)->ok);
printf("Age : %d\n",(t+i)->age);
printf("Hours : %d\n",(t+i)->hr);
printf("ID : %d\n",(t+i)->id);
}
}
fclose(f);
}
//emp* modf(emp *t,int n){
// int i;
// int k;
// char nv[50];
// printf("id of the entry you want to be modified" );
// scanf("%d\n",&k);
// for(i=0;i<n;i++){
// if(k==(t+i)->id){
// scanf("%s",&nv);
// (t+i)->name=nv;
// }
// }
// return t;
//}
//void del(emp *t,int n){
// int i;
// emp a;
// int k;
// printf("position of the entry you want to delete?");
// scanf("%d",&a);
// for(i=0;i<n;i++){
// if (a == *(t+i)) {
// for(i=k;i<n-1;i++){
// *(t+i)=*(t+i+1);
// }
// }
// }
//}
int main(int argc, char *argv[]){
int c;
emp e;
emp *k;
k=&e;
int n;
emp *t;
t=&e;
char p;
ka:
printf("Welcome To The employe management Menu\n");
printf("1.Add employes?\n");
printf("2.show all employes?\n");
printf("3.delete an entry?\n");
scanf("%d",&c);
switch (c){
case 1:
ed:
printf("How many employes you want to add?\n");
scanf("%d",&n);
add(k,n);
if(p=='y'){
goto ed;
}
else goto ka;
break;
case 2:
aff(t,n);
break;
case 3:
del(t,n);
break;
}
return 0;
}
At least these issues:
Wrong allocation size #Weather Vane
Avoid allocation errors. Allocate to the size of the refenced object, not the type.
// t=(emp*)malloc(n*sizeof(int));
t = malloc(sizeof t[0] * n);
Easier to code right, review and maintain.
Uninitialized p #Craig Estey
f(p=='y') is undefined behavior as p is uninitialized.
This hints that OP is not compiling with all warnings enabled. Save time - enable all warnings.
emp not defined
Perhaps OP is not using a C compiler, but a C++ one?
i not defined in for (i = 0; i < n; i++) {
Is int I; the true code?
Bad "%s"
Without a width, "%s" is worse than gets(). Use a width like "%49s".
I have to create a program that has an array of costumers (structs that contain name, code and documentation) and functions to insert, remove and list all of them in order of code. I'm not understanding what I should do. Please note that the parameters for insertCostumer, removeCostumer and listCostumer cannot be changed.
Piece of code 01:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#define MAX_REG 10
typedef struct _costumer {
int code;
char name[50];
char documentation[20];
} costumer;
Piece of code 02:
int main(int argc, char** argv) {
costumer *costumers[MAX_REG];
costumer **p_costumer;
p_costumer = &costumers[0];
int count = 0;
memset(costumers, 0, sizeof(costumers));
//Some code to check what to do using a switch
case '1': insertCostumer(p_costumer, &count); getch(); break;
case '2': removeCostumer(p_costumer, &count); getch(); break;
case '3': listCostumers(p_costumer, &count); getch(); break;
//Some code
return (EXIT_SUCCESS);
}
Piece of code 03:
void insertCostumer(costumer **p_costumer, int *count){
char aux[50];
char aux2[20];
if(*count < MAX_REG) {
*p_costumer = (costumer *) malloc(sizeof(costumer));
printf("\nInsert the code: ");
gets(aux);
(*p_costumer)->code = atoi(aux);
printf("Insert the name: ");
gets(aux);
strcpy((*p_costumer)->name, aux);
printf("Insert the documentation: ");
gets(aux2);
strcpy((*p_costumer)->documentation, aux2);
(*count)++;
p_costumer = &*p_costumer[*count];
} else {
printf("List full! Remove a costumer first!\n");
}
}
void removeCostumer(costumer **p_costumer, int *count){
char aux3[50];
int cod;
printf("\nInsert the code of the costumer to be removed: ");
gets(aux3);
cod = atoi(aux3);
for(int i = 0; i < *count; i++) {
if(p_costumer[i]->code == cod) {
strcpy(p_costumer[i]->name, NULL);
p_costumer[i]->code = 0;
strcpy(p_costumer[i]->documentation, NULL);
}
}
}
void listCostumers(costumer **p_costumer, int *count){
for(int i = 0; i < *count; i++) {
printf("Code: %d | Name: %s | Documentation: %s\n", p_costumer[i]->code, p_costumer[i]->name, p_costumer[i]->documentation);
}
}
I don't know what I'm doing wrong; nothing is working, honestly. I was trying to first insert, list and remove to try and make the sorting part later, but I can't even get this part done. When I list, only the last costumer added is listed, for example.
Can someone help me?
Okay, I had to refactor a considerable amount of your code, so I don't have a blow by blow description of the changes.
You'll just have to study it a bit.
Note that even if you're passed a double pointer as an argument, doesn't mean you have to use it as a double in the body of the functions. Note, in particular, what I did for the count (e.g. int count = *p_count; and *p_count = count;)
But, it should be noted that the list is one of pointers to structs and not merely a pointer to an array of structs (i.e. there is an extra level of indirection). This makes things a bit faster.
Note that, bug fixes aside, the key is the "slide" operation in the remove function.
Because we're "sliding" pointers, this is faster/more efficient with the pointer array. Study this [concept] well.
Never use gets--always use fgets
I've deliberately left off comments. This will allow you to add them as you analyze the code. I've found that this can be a powerful technique for understanding a [foreign] code base.
Anyway, here's the code. I've done some rudimentary testing and it seems to work:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#include <conio.h>
#define MAX_REG 10
char aux[1000];
typedef struct _costumer {
int code;
char name[50];
char documentation[20];
} costumer;
void
lineget(char *buf,size_t buflen)
{
char *cp;
cp = fgets(buf,buflen,stdin);
if (cp != NULL) {
cp = strrchr(buf,'\n');
if (cp != NULL)
*cp = 0;
}
}
void
insertCostumer(costumer **p_costumer, int *p_count)
{
costumer *add;
int count = *p_count;
char aux2[20];
if (count < MAX_REG) {
add = malloc(sizeof(costumer));
printf("\nInsert the code: ");
lineget(aux,sizeof(aux));
add->code = atoi(aux);
printf("Insert the name: ");
lineget(add->name,sizeof(add->name));
printf("Insert the documentation: ");
lineget(add->documentation,sizeof(add->documentation));
p_costumer[count] = add;
++count;
}
else {
printf("List full! Remove a costumer first!\n");
}
*p_count = count;
}
void
removeCostumer(costumer **p_costumer, int *p_count)
{
int count = *p_count;
int cod;
int i;
costumer *cur;
printf("\nInsert the code of the costumer to be removed: ");
fgets(aux,sizeof(aux),stdin);
cod = atoi(aux);
int slide = 0;
for (i = 0; i < count; i++) {
cur = p_costumer[i];
if (cur->code == cod) {
slide = 1;
break;
}
}
if (slide) {
free(cur);
--count;
for (; i < count; ++i)
p_costumer[i] = p_costumer[i + 1];
p_costumer[count] = NULL;
}
*p_count = count;
}
void
listCostumers(costumer **p_costumer, int *p_count)
{
costumer *cur;
int count = *p_count;
for (int i = 0; i < count; ++i, ++cur) {
cur = p_costumer[i];
printf("Code: %d | Name: %s | Documentation: %s\n",
cur->code, cur->name, cur->documentation);
}
}
int
main(int argc, char **argv)
{
costumer *costumers[MAX_REG];
costumer **p_costumer;
char buf[100];
p_costumer = &costumers[0];
int count = 0;
memset(costumers, 0, sizeof(costumers));
setbuf(stdout,NULL);
//Some code to check what to do using a switch
while (1) {
printf("operation to perform (1=insert, 2=remove, 3=print): ");
char *cp = fgets(buf,sizeof(buf),stdin);
if (cp == NULL)
break;
switch (cp[0]) {
case '1':
insertCostumer(p_costumer, &count);
break;
case '2':
removeCostumer(p_costumer, &count);
break;
case '3':
listCostumers(p_costumer, &count);
break;
}
}
return (EXIT_SUCCESS);
}
In my code I have allocated some memory with my struct Song pointer called ptr
.
What I'm now trying to do is to create a second pointer that always point to the first struct in the allocated memory and use that to loop through all when I want to print the information.
It looks something like this in main:
#include "FuncDek.h"
#include <locale.h>
#include <crtdbg.h>
int main()
{
//For swedish and check memory leak
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
setlocale(LC_ALL, "swedish");
//Create with starting size of 5
Song *ptr = (Song *)malloc(sizeof(Song) * 5);
Song *start = &(ptr[0]);
int menuChoice = 0;
int nrOfSongs = 0;
do
{
system("cls");
menuChoice = menu();
switch (menuChoice)
{
case 1:
addSong(&ptr, &nrOfSongs);
break;
case 2:
showList(&start, nrOfSongs, &ptr);
break;
default:
printf("\nFelaktigt val, försök igen\n");
system("pause");
break;
}
} while (menuChoice != 0);
//TODO Free memory
//free(ptr);
system("pause");
return 0;
}
And I have to files that contains the function declarations/definitions which looks something like this:
#ifndef FUNCDEK
#define FUNCDEK
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char title[30];
char artist[30];
unsigned int year;
} Song;
int menu();
void addSong(Song *ptr, int *nrOfSongs);
void showList(Song *start, int nrOfSongs, Song *ptr);
#endif
And:
#include "FuncDek.h"
#pragma warning(disable: 4996)
//Show menu and save the users choice
int menu()
{
fflush(stdin);
int choice = 0;
printf("Menyval på låtlista\n");
printf("-------------------------\n");
printf("1. Lägg till låt \n");
printf("2. Visa låtlista \n");
printf("3. Blanda låtlistan \n");
printf("4. Spara till fil \n");
printf("0. Avsluta program \n");
scanf("%d", &choice);
getchar();
/*TODO FELHANTERING*/
return choice;
}
//Add song to list
void addSong(Song *ptr, int *nrOfSongs)
{
system("cls");
Song temp;
printf("Ange låtens namn:\n");
int sizeOfTitle = sizeof(temp.title) / sizeof(temp.title[0]);
fgets(temp.title, sizeOfTitle, stdin);
printf("Ange artistens namn:\n");
int sizeOfArt = sizeof(temp.artist) / sizeof(temp.artist[0]);
fgets(temp.artist, sizeOfArt, stdin);
printf("Ange året låtens släpptes: \n");
scanf("%d", &temp.year);
for (int i = 0; i < sizeOfTitle; i++)
{
ptr->artist[i] = temp.artist[i];
ptr->title[i] = temp.title[i];
}
ptr->year = temp.year;
*ptr++;
*nrOfSongs = *nrOfSongs + 1;
}
//Print all from list
void showList(Song *start, int nrOfSongs, Song *ptr)
{
system("cls");
printf("Song list\n");
printf("-----------------------------\n");
for (int i = 0; i < 1; i++)
{
printf("Låt: %s \n", start->title);
printf("Artist: %s \n", start->artist);
printf("År: %d \n", start->year);
start++;
}
system("pause");
}
But when I run the showList function I get garbage values and I can also see that I don't read on the correct memory-location.
So my questions is how do I make my pointer called start to point to the first memory block in ptr?
You can consider using a C linked list.
Here is a good example.
I have come across this wierd and mysterous (at least to me) error that I am finding a very hard time finding. It gives me an error at the line where I call my function input(student_list1[MAX], &total_entries); where the compiler says:
incompatible type for agument 1 in 'input'
What am I doing wrong here? I sense it something very simple and stupid but I have gone through the code several times now without any avail.
#define MAX 10
#define NAME_LEN 15
struct person {
char name[NAME_LEN+1];
int age;
};
void input(struct person student_list1[MAX], int *total_entries);
int main(void)
{
struct person student_list1[MAX];
int total_entries=0, i;
input(student_list1[MAX], &total_entries);
for(i=0; i<total_entries; i++)
{
printf("Student 1:\tNamn: %s.\tAge: %s.\n", student_list1[i].name, student_list1[i].age);
}
return 0;
} //main end
void input(struct person student_list1[MAX], int *total_entries)
{
int done=0;
while(done!=1)
{
int i=0;
printf("Name of student: ");
fgets(student_list1[i].name, strlen(student_list1[i].name), stdin);
student_list1[i].name[strlen(student_list1[i].name)-1]=0;
if(student_list1[i].name==0) {
done=1;
}
else {
printf("Age of student: ");
scanf("%d", student_list1[i].age);
*total_entries++;
i++;
}
}
}
struct person student_list1[MAX] in the function argument is actually a pointer to struct person student_list1.
student_list1[MAX] you passed is a (out of bound) member of the array struct person student_list1[MAX]. Valid array index shoudl be between 0 to MAX - 1.
Change it to:
input(student_list1, &total_entries);
Note that here the array name student_list1 is automatically converted to a pointer to student_list1[0].
There are many things wrong with the code; this is my attempt at making it somewhat more robust:
#include <stdio.h>
#include <string.h>
#define MAX 10
#define NAME_LEN 15
// use a typedef to simplify code
typedef struct person {
char name[NAME_LEN];
int age;
} person_t;
// size qualifier on student_list is redundent and person_t* does the same
void input(person_t *student_list, int *total_entries);
int main(void)
{
person_t student_list[MAX];
int total_entries, i;
// pass array and not the non-existent 'student_list[MAX]' element
input(student_list, &total_entries);
for(i=0; i<total_entries; i++)
{
// age is an int, not a string so use %d
printf("Student 1:\tName: %s.\tAge: %d.\n", student_list[i].name, student_list[i].age);
}
return 0;
} //main end
void input(person_t *student_list, int *total_entries)
{
int done = 0, i = 0;
*total_entries = 0;
while (i < MAX) {
printf("Name of student: ");
// use NAME_LEN instead of strlen(list[i].name) because latter is
// probably not initialized at this stage
if (fgets(student_list[i].name, NAME_LEN, stdin) == NULL) {
return;
}
// detect zero-length string
if (student_list[i].name[0] == '\n') {
return;
}
printf("Age of student: ");
scanf("%d", &student_list[i].age);
// read the newline
fgetc(stdin);
*total_entries = ++i;
}
}
input(student_list1[MAX], &total_entries); shoud be input(student_list1, &total_entries);.
In C,
void input(struct person student_list1[MAX], int *total_entries);
equals
void input(struct person *student_list1, int *total_entries);