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);
}
Related
I'm trying to create an array of Product structs and then print the name and code of each Product in the array, but I keep getting a segmentation fault. I have tried to insert each value without a loop and then printing, and it works, but I'd like to automate it. The function fill_products fills the products array according to the user's input, and the select_products prints each name-code pair for the entire array.
This is my code:
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int code;
char *name;
float price;
} Product;
void select_products(Product *products, int len)
{
int i;
printf("%-30s%s\n", "Name", "Code");
for (i = 0; i < len; i++)
{
printf("%-30s%d\n", products[i].name, products[i].code);
}
return;
}
void fill_products(Product *products, int len)
{
int i, code;
char *name;
float price;
for (i = 0; i < len; i++)
{
printf("Insert product name (%d / %d): ", i + 1, len);
scanf("%s", &name);
printf("Insert product price (%d / %d): ", i + 1, len);
scanf("%f", &price);
products[i].code = i;
products[i].name = name;
products[i].price = price;
}
return;
}
int is_alloc(Product *products)
{
if (products == NULL)
{
printf("Error: memory allocation unsuccessful.\n");
}
return products != NULL;
}
int main(void)
{
int len, n_bytes;
Product *products;
printf("Insert length of array: ");
scanf("%d", &len);
n_bytes = sizeof *products * len;
products = malloc(n_bytes);
if(!is_alloc(products))
{
exit(0);
}
fill_products(products, len);
select_products(products, len);
free(products);
return 0;
}
I keep getting a segmentation fault.
Please enable compiler warnings, and pay attention to them.
This code:
char *name;
...
scanf("%s", &name);
is bogus and doesn't do at all what you intend.
You must either allocate space for name separately (and then not forget to free() it), or make that space available in the Product structure like so:
typedef struct
{
int code;
char name[100];
float price;
} Product;
(this assumes there is a reasonable limit on name length).
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
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);
}
I am trying to free the memory allocated by my getSongInfo function, I have tried using a pointer to the function call but I get an error "cannt assign int to type int*" error. Any help would be great as the current way I have seems like it may work, but I might be completely wrong. Thanks!
Original Attempt:
int *memPtr = NULL
memPtr = getSongInfo(&fillPtr[arrayCounter], tempArtist[counter], tempSong[counter]);
Gives error!
Current Attempt:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#pragma warning(disable:4996)
int getSongInfo(struct songInfo *pFillInfo, char *artistName, char *songName);
void printSongInfo(struct songInfo songList[10]);
struct songInfo {
char *songArtist;
char *songTitle;
};
int main(void)
{
struct songInfo *fillPtr;
struct songInfo songList[10];
fillPtr = &songList[0];
char tempArtist[10][30];
char tempSong[10][30];
int *memPtr = NULL;
int i = 0;
int counter = 0;
int arrayCounter = 0;
while (counter != 10)
{
printf("Please enter the artist name: ");
fgets(tempArtist[counter], sizeof(tempArtist[counter]), stdin);
tempArtist[counter][strcspn(tempArtist[counter], "\n")] = 0;
printf("Please enter the song name: ");
fgets(tempSong[counter], sizeof(tempSong[counter]), stdin);
tempSong[counter][strcspn(tempSong[counter], "\n")] = 0;
getSongInfo(&fillPtr[arrayCounter], tempArtist[counter], tempSong[counter]);
printf("Song and Artist Captured! \n");
counter++;
arrayCounter++;
}
printSongInfo(fillPtr);
free(fillPtr->songArtist);
free(fillPtr->songTitle);
}
int getSongInfo(struct songInfo *pFillInfo, char *artistName, char *songName)
{
pFillInfo->songArtist = (char*)malloc(strlen(artistName) + 1);
pFillInfo->songTitle = (char*)malloc(strlen(songName) + 1);
strcpy(pFillInfo->songArtist, artistName);
strcpy(pFillInfo->songTitle, songName);
return 1;
}
void printSongInfo(struct songInfo songList[10])
{
int counter = 0;
while (counter != 10)
{
printf("%-35s %-35s\n", songList[counter].songArtist, songList[counter].songTitle);
counter++;
}
}
Your getSongInfo function does not return a pointer, so attempting to put the return value into a variable and then free it is pointless. The pointers in question are inside the struct songInfo, specifically, the fillPtr variable (which is actually redundant, since songList and fillPtr point to the same location).
In addition, please be aware that strcspn will not always return a valid index. If it does not find a match, it will return the length of the first argument.
I think this is more like what you are trying to do:
int main(void)
{
const int numSongs = 10;
struct songInfo songList[numSongs];
char tempArtist[30];
char tempSong[30];
int i;
int newline_idx;
for (i = 0; i < numSongs; ++i)
{
printf("Please enter the artist name: ");
fgets(tempArtist, sizeof(tempArtist), stdin);
newline_idx = strcspn(tempArtist, "\n");
if (newline_idx < sizeof(tempArtist))
tempArtist[newline_idx] = 0;
printf("Please enter the song name: ");
fgets(tempSong, sizeof(tempSong), stdin);
newline_idx = strcspn(tempSong, "\n");
if (newline_idx < sizeof(tempSong))
tempSong[newline_idx] = 0;
getSongInfo(&songList[i], tempArtist, tempSong);
printf("Song and Artist Captured! \n");
}
for (i = 0; i < numSongs; ++i)
{
free(songList[i].songArtist);
free(songList[i].songTitle);
}
}
You might consider separating the code for free()ing each struct into its own function.
You might also consider heeding that compiler warning instead of ignoring it, as Bodo commented. Careless handling of strings from stdin is dangerous.
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);