Double pointer with array in another function - c

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);
}

Related

Allocating the proper memory for a function that recieves a structure

Im trying to create a dynamic database where I can modify its size.
This is the code that I have written so far where I assign the product char pointer to null and price to -1
What I would expect for it is to have created the data base and let me keep creating new ones with new sizes which replace the old database but so far it only returns a memory direction and stops the program.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct _product_t {
char *product;
float price;
} product_t;
product_t *newDatabase(product_t *database, int *dbSize, int newSize) {
free(database);
product_t *newdatabase = (product_t*)malloc(sizeof(database)*newSize);
newdatabase->product = (char*)malloc(sizeof(char)*20);
newdatabase->product = NULL;
newdatabase->price = -1;
free(newdatabase->product);
return newdatabase;
}
int main(void) {
product_t *database = NULL;
int dbSize = 0;
char cmd;
do{
printf("Command?");
scanf(" %c", &cmd);
switch (cmd) {
case 'q':
printf("Bye!");
break;
case 'n':
printf("Size? ");
int newSize2 = 0;
scanf("%d", newSize2);
newDatabase(database, &dbSize, newSize2);
break;
default:
printf("Unkown command '%c'\n",cmd);
}
}while(cmd != 'q');
return 0;
}
Use realloc() to change the size of an allocation. The size of the array should use sizeof(*database), since sizeof(database) is just the size of a pointer, not the size of the structure.
When initializing the new array elements, you need a loop. newdatabase points to the beginning of the array, not the new elements that were added.
product_t *newDatabase(product_t *database, int *dbSize, int newSize) {
// Free the old `product` pointers if we're shrinking
for (int i = newSize; i < *dbSize; i++) {
free(database[i].product);
}
product_t *newdatabase = realloc(database, sizeof(*database)*newSize);
if (!newdatabase && newSize != 0) {
printf("Unable to allocate memory\n");
exit(1);
}
// initialize the new pointers if we're growing
for (int i = *dbSize; i < newSize; i++) {
newdatabase[i].product = malloc(sizeof(char)*20);
newdatabase[i].price = -1;
}
*dbSize = newSize;
return newdatabase;
}
You also need to fix the line that asks for the size:
scanf("%d", newSize2);
Except when reading a string, you need to pass the address of the variable to write into, so it should be:
scanf("%d", &newSize2);
Latest fully working version, thanks a lot for the help everyone!
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct _product_t {
char *product;
float price;
} product_t;
product_t *newDatabase(product_t *database, int *dbSize, int newSize) {
// Free the previous memory allocated for the database
free(database);
// Allocate new space for newSize products on the heap
database = (product_t*) malloc(newSize * sizeof(product_t));
// Initialize all products in the database with NULL and -1
for (int i = 0; i < newSize; i++) {
database[i].product = NULL;
database[i].price = -1;
}
// Update the database size
*dbSize = newSize;
// Return the pointer to the new database
return database;
}
int main(void) {
product_t *database = NULL;
int dbSize = 0;
char cmd;
do{
printf("Command?");
scanf(" %c", &cmd);
switch (cmd) {
case 'q':
printf("Bye!");
break;
case 'n':
printf("Size? ");
int newSize2 = 0;
scanf("%d", &newSize2);
if(newSize2 < 0) {
printf("Must be larger than 0");
break;
}
else{
database = newDatabase(database, &dbSize, newSize2);
break;
}
default:
printf("Unkown command '%c'\n",cmd);
}
}while(cmd != 'q');
return 0;
}
Working solution was found through the help of everyone thanks

how to do a delete and modify function correctly

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".

Unable to assign the value to structure member using double pointer

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

How to print string into an array after used the isdigit?

I'm very new to isdigit and the string. I really need help from you guys. I want to print string into an array 'food[f]'.But can you guys help me to check where is my problem ? Here is my code.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main()
{
char foo[20];
float price;
int number=1;
int f=0,i=0;
char *food[f];
adding_food :
food[f] = (char*)malloc(25);
printf("Adding food into Menu (0 to Main Menu): ");
scanf("%s", foo);
{
if(isdigit(foo[0])== 0)
{
foo[i] = *food[f]; //something wrong here
printf("Enter price (RM) : ");
scanf("%f",&price);
printf("\n%-16d%-19s%6.2f\n\n",number,foo,price);
printf("\n%-16d%-19s%6.2f\n\n",number,food[f],price);
number++;
i++;
f++;
goto adding_food;
}
else
return 0;
}
}
I would like my output be like this
Adding food into Menu (0 to Main Menu) : Cake
Enter price (RM) : 10
1 Cake 10 //foo[0]
1 Cake 10 //food[0]
There are several mistakes in your code. Example:
char *food[f];
is similar to
char *food[0];
as f is zero. That makes no sense.
Also the use of goto is not considered good style.
So let me show you another approach. Something like:
// Make a type that can hold both a name and a price
struct item
{
char name[25];
float price;
};
#define MAX_ITEMS 100
struct item* addItems(int* n)
{
*n = 0;
struct item* items = malloc(MAX_ITEMS * sizeof *items);
if (items == NULL) return NULL;
while (*n != MAX_ITEMS)
{
scanf("%24s", items[*n].name);
if (items[*n].name[0] == '0') break;
scanf("%f", &items[*n].price);
*n += 1;
}
return items;
}
void print_all(struct item* my_items, int num_items)
{
for (int i = 0; i < num_items; ++i)
printf("%s %f\n", my_items[i].name, my_items[i].price);
}
int main()
{
int num_items;
struct item* my_items = addItems(&num_items);
print_all(my_items, num_items);
free(my_items);
}

Point struct pointer to first block of dynamic allocated memory in C

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.

Resources