I want to ask about file processing and struct in C language, I get an assignment from my lecture, and am so really confused about string manipulation in C programming. Here is the task.
get data from mhs.txt
store in struct
sort by name ascending
Here is the mhs.txt
1701289436#ANDI#1982
1701317124#WILSON#1972
1701331734#CHRISTOPHER STANLEY#1963
1701331652#SHINVANNI THEODORE#1962
1701331141#MUHAMMAD IMDAAD ZAKARIA#1953
1701331564#MARCELLO GENESIS DRIET J.#1942
1701322282#ANANDA AULIA#1972
1701329175#LORIS TUJIBA SOEJONOPOETRO#1983
1701301422#DEWI JULITA#1993
1701332610#HARRY HUTALIANG#1982
first before # is NIM,
after first # is name
and the last after #, is year
and here is what i've done
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct student{
char nim[11];
char name[50];
int year;
}s[10];
int main(){
FILE *fp;
int c,i,n;
printf("Read mhs.txt...");
getchar();
fp = fopen("mhs.txt", "r");
c = getc(fp);
i = 0;
while(c!=EOF){
printf("%c", c);
c = getc(fp);
i++;
}
fclose(fp);
getchar();
return 0;
}
First thing, I could save data on struct, but in here I very confused to separate a string.
That's all I know about struct and file processing, is there anyone who can help me? I have traveled around the internet and could not find the correct results.
Sorry if there are duplicate questions, and sorry if my english is too bad.
This is pure C code, you should new three import function: strtok & qsort & fsan.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct student
{
char nim[11];
char name[50];
int year;
};
#define BUFFER_SIZE 100
struct student saveToStruct (char* str)
{
struct student res;
int flag = 0;
char *token = strtok(str, "#");
while( token != NULL )
{
if (0 == flag)
strcpy(res.nim, token);
else if (1 == flag)
strcpy(res.name, token);
else
res.year = atoi(token);
flag++;
token = strtok( NULL, "#" );
}
return res;
}
void print(struct student* arr, int size)
{
for (int i = 0; i < size; i++)
{
printf("%s, %s, %d\n", arr[i].nim, arr[i].name, arr[i].year);
}
}
int cmp(const void* l, const void* r)
{
return strcmp(((const student*)l)->name, ((const student*)r)->name);
}
int main()
{
struct student arr[10];
FILE* file = fopen("mhs.txt", "r");
if (!file)
return -1;
char buffer[BUFFER_SIZE];
int flag = 0;
while (fgets(buffer, BUFFER_SIZE, file))
{
arr[flag] = saveToStruct(buffer);
flag++;
}
print(arr, 10);
qsort(arr, 10, sizeof(struct student), cmp);
printf("After sort by name!\n");
print(arr, 10);
return 0;
}
Since you've tagged this as C++, I'd use C++:
#include <iostream>
#include <string>
#include <algorithm>
struct student {
std::string nim;
std::string name;
int year;
bool operator<(student const &other) {
return name < other.name;
}
friend std::istream &operator>>(std::istream &is, student &s) {
std::getline(is, s.nim, '#');
std::getline(is, s.name, '#');
return is >> s.year;
}
};
int main() {
std::ifstream in("mhs.txt");
std::vector<student> students{
std::istream_iterator<student>(in),
std::istream_iterator<student>()
};
std::sort(students.begin(), students.end());
}
If you want to accomplish roughly the same thing in C, it's probably easiest to do the reading with fscanf using a scanset conversion, like:
fscanf(infile, "%10[^#]#%49[^#]#%d", student.nim, student.name, &student.year);
The scanset conversion gives you something like a subset of regular expressions, so the %[^#] converts a string of characters up to (but not including) a #. In this case, I've limited the length of each to one less than the length you gave for the arrays in your struct definition to prevent buffer overruns.
Then you can do the sorting with qsort. You'll need to write a comparison function, and doing that correctly isn't always obvious though:
int cmp(void const *aa, void const *bb) {
student const *a = aa;
student const *b = bb;
return strcmp(a->name, b->name);
}
Here are some hints, not the full answer. Hope it could help you.
first you need to read the file line by line, instead of character by character. You need the function of fgets(). you may find the reference from www.cplusplus.com/reference/cstdio/fgets/
second you can use strtok() to seperate strings. here is an example.
char str[] = "now # is the time for all # good men to come to the # aid of their country";
char delims[] = "#";
char *result = NULL;
result = strtok( str, delims );
while( result != NULL ) {
printf( "result is \"%s\"\n", result );
result = strtok( NULL, delims );
}
and you may find the reference to strtok() from http://www.cplusplus.com/reference/cstring/strtok/
third, use qsort() to sort the structure array. you may find the reference of it from http://www.cplusplus.com/reference/cstdlib/qsort/. examples can also be found there.
Related
Before proceeding with PSET5 - SPELLER of the CS50 course, I have decided to practice with a made-up program that takes words from a file and sorts them into a Hash Table, but I think I`m doing something wrong with the Hash Function as I keep getting the following error:
array subscript is not an integer
table[hash] = n;
Some of the elements are taken from the task itself to understand how they work. I don`t have any previous knowledge, totally limited to the CS50 course.
Please have a look at my code and maybe give a few pointers to what I am doing wrong.
From what I understand - every new word`s first letter goes through Hash Functions and returns a number for the Bucket in which this word goes.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int hash(const char *buffer);
const unsigned int LENGTH = 9;
typedef struct node
{
char word[LENGTH + 1];
struct node* next;
}
node;
node *table[26] = {NULL};
int hash(const char *buffer)
{
return toupper(buffer[0]) - 'A';
}
int main(void)
{
FILE *file = fopen("words", "r");
if (file != NULL)
{
char buffer[LENGTH];
while (fscanf(file, "%s", buffer) != EOF)
{
node *n = malloc(sizeof(node));
if (n == NULL)
{
return 1;
}
strcpy(n->word, buffer);
n->next = NULL;
table[hash] = n;
}
fclose(file);
}
}
You need to call the function hash(..) , it is not a variable.
Your line should be:
table[ hash(n->word) ] = n;
I have currently made this much of the code:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <ctype.h>
#define STRSIZE 21
struct PInven{
int count;
struct PItem{
char name[STRSIZE];
int amount;
}Pitem;
}Pinven;//this needs to be an output file
int ReadInProduce (){
//read in file and check to see if the file exist or not.
FILE * PinFile = fopen("produce.txt","r");
if (PinFile == NULL){
printf("ERROR: WRONG FILE");
}
else{
printf("I did it!!\n");
}
//assigning the value gotten into the struct variable(but need to maybe change this since it needs to be an output)
fscanf(PinFile,"%d",&Pinven.count);
printf("%d\n", Pinven.count);
int i;
for(i =0; i <Pinven.count; i++){
fscanf(PinFile,"%20s %d",Pinven.Pitem.name, &Pinven.Pitem.amount);
printf("%s %d\n",Pinven.Pitem.name, Pinven.Pitem.amount);
}
//making an array to hold the variables
//FILE * PoutFile = fopen("produce_update.txt","w");
fclose(PinFile);
return 0;
}
From there I want to get the file that is read to the structs to be printed out into an array so that later on I can make a function that will be able to compare to the to it.
Basically a store management system. Where the file of the inventory is read in and compared to the file that is store and return a new value for the amount of produce now either left or gained.
10 //number of items that will be stored in the store
apple 19
banana 31
broccoli 9
...
In general, it's a really bad idea to include header information in the file about the number of entries in the file. You want to be able to do stream processing, and that will be more difficult if you need that meta-data. More importantly, it is important to understand how to write the code so that you don't need it. It's not really that difficult, but for some reason people avoid it. One simple approach is just to grow the array for each entry. This is horribly inefficient, but for the sake of simplicity, here's an example that expects the file not not include that first line:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <ctype.h>
#include <limits.h>
#define STRSIZE 128
struct PItem{
char name[STRSIZE];
int amount;
};
struct PInven{
int count;
struct PItem *PItem;
};
static void
grow(struct PInven *p)
{
p->PItem = realloc(p->PItem, ++p->count * sizeof *p->PItem);
if( p->PItem == NULL ){
perror("out of memory");
exit(1);
}
}
int
ReadInProduce(struct PInven *P, const char *path)
{
FILE * PinFile = fopen(path, "r");
if( PinFile == NULL ){
perror(path);
exit(1);
}
char fmt[64];
int max_len;
max_len = snprintf(fmt, 0, "%d", INT_MAX);
snprintf(fmt, sizeof fmt, "%%%ds %%%dd", STRSIZE - 1, max_len - 1);
grow(P);
struct PItem *i = P->PItem;
while( fscanf(PinFile, fmt, i->name, &i->amount) == 2 ){
i += 1;
grow(P);
}
P->count -= 1;
fclose(PinFile); /* Should check for error here! */
return P->count;
}
int
main(int argc, char **argv)
{
struct PInven P = {0};
char *input = argc > 1 ? argv[1] : "produce.txt";
ReadInProduce(&P, input);
struct PItem *t = P.PItem;
for( int i = 0; i < P.count; i++, t++ ){
printf("%10d: %s\n", t->amount, t->name);
}
}
As an exercise for the reader, you should add some error handling. At the moment, this code simply stops reading the input file if there is bad input. Also, it would be a useful exercise to do fewer reallocations.
you should change Structure of PInven to it can save a dynamic array of Pitem with a Pitem pointer.
tested :
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#define STRSIZE 21
typedef struct {
char name[STRSIZE];
int amount;
} Pitem;
struct PInven {
int count;
Pitem *pitem;
} Pinven; // this needs to be an output file
int main() {
// read in file and check to see if the file exist or not.
FILE *PinFile = fopen("produce.txt", "r");
if (PinFile == NULL) {
printf("ERROR: WRONG FILE");
} else {
printf("I did it!!\n");
}
// assigning the value gotten into the struct variable(but need to maybe
// change this since it needs to be an output)
fscanf(PinFile, "%d", &Pinven.count);
Pinven.pitem = (Pitem *)malloc(sizeof(Pitem) * Pinven.count);
printf("%d\n", Pinven.count);
int i;
for (i = 0; i < Pinven.count; i++) {
fscanf(PinFile, "%20s %d", Pinven.pitem[i].name,
&Pinven.pitem[i].amount);
// printf("%s %d\n",Pinven.pitem[i].name, Pinven.pitem[i].amount);
}
for (i = 0; i < Pinven.count; i++) {
printf("%s %d\n", Pinven.pitem[i].name, Pinven.pitem[i].amount);
}
// making an array to hold the variables
// FILE * PoutFile = fopen("produce_update.txt","w");
fclose(PinFile);
// remember free
free(Pinven.pitem);
return 0;
}
I am required to organize the following c code into header (s) and c file (s). However, im unable to do so myself.
The code is as follows:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFER_SIZE 256
#define PROGRAMMES_SIZE 2
#define DELIMETER ","
struct programme
{
char name[32];
char code[8];
int credits;
};
struct programme parseProgramme(char *);
struct programme createProgramme(char[], char[], int);
void printProgramme(struct programme);
void updateProgrammeName(struct programme *, char[]);
int main()
{
char buffer[BUFFER_SIZE];
struct programme programmes[PROGRAMMES_SIZE];
FILE *input = fopen("input", "r");
if (input == NULL)
exit(1);
int i;
for (i = 0; i < PROGRAMMES_SIZE; i++)
{
fgets(buffer, BUFFER_SIZE, input);
programmes[i] = parseProgramme(buffer);
}
for (i = 0; i < PROGRAMMES_SIZE; i++)
printProgramme(programmes[i]);
fclose(input);
return 0;
}
struct programme parseProgramme(char *buffer)
{
char name[32];
char code[8];
int credits;
// parse name
strcpy(name, strtok(buffer, DELIMETER));
// parse code
strcpy(code, strtok(NULL, DELIMETER));
// parse credits
credits = atoi(strtok(NULL, DELIMETER));
return createProgramme(name, code, credits);
}
struct programme createProgramme(char name[], char code[], int credits)
{
struct programme programme;
strcpy(programme.name, name);
strcpy(programme.code, code);
programme.credits = credits;
return programme;
}
void printProgramme(struct programme programme)
{
puts(programme.name);
puts(programme.code);
printf("%d\n", programme.credits);
}
void updateProgrammeName(struct programme *programme, char name[])
{
strcpy(programme->name, name);
}
Please be noted that its not required to update any of the following definitions or implementations of the code listed above, stated by my collage professor. Just to organize them accordingly, any help is apricated!.
There is no strict need to create a separate header file here, because there is no code re-use.
However, if some of the code were to be reused in other files, then it would start to make sense. So let's say we want to move some functionality to a library.
Then it would make sense to split up the functions to a separate file, and create a header file which would also be roughly representing the API.
So let's skip some code and look at main.c:
int main()
{
char buffer[BUFFER_SIZE];
struct programme programmes[PROGRAMMES_SIZE];
FILE *input = fopen("input", "r");
if (input == NULL)
exit(1);
int i;
for (i = 0; i < PROGRAMMES_SIZE; i++)
{
fgets(buffer, BUFFER_SIZE, input);
programmes[i] = parseProgramme(buffer);
}
for (i = 0; i < PROGRAMMES_SIZE; i++)
printProgramme(programmes[i]);
fclose(input);
return 0;
}
And obviously the functions would be in e.g. program.c:
struct programme parseProgramme(char *buffer)
{
char name[32];
char code[8];
int credits;
// parse name
strcpy(name, strtok(buffer, DELIMETER));
// parse code
strcpy(code, strtok(NULL, DELIMETER));
// parse credits
credits = atoi(strtok(NULL, DELIMETER));
return createProgramme(name, code, credits);
}
struct programme createProgramme(char name[], char code[], int credits)
{
struct programme programme;
strcpy(programme.name, name);
strcpy(programme.code, code);
programme.credits = credits;
return programme;
}
void printProgramme(struct programme programme)
{
puts(programme.name);
puts(programme.code);
printf("%d\n", programme.credits);
}
void updateProgrammeName(struct programme *programme, char name[])
{
strcpy(programme->name, name);
}
Now we can easily see, that PROGRAMMES_SIZE and BUFFER_SIZE are not used in the functions, and should be defined in main.c.
On the other hand, DELIMETER is only used in the functions, so it should be defined at the top in program.c.
We can move the struct and function definitions to program.h. It's good practice to prevent recursive inclusion, we could use some simple ifndef for that:
#ifndef PROGRAM_H
#define PROGRAM_H
struct programme
{
char name[32];
char code[8];
int credits;
};
struct programme parseProgramme(char *);
struct programme createProgramme(char[], char[], int);
void printProgramme(struct programme);
void updateProgrammeName(struct programme *, char[]);
#endif /* PROGRAM_H */
Finally, you should look which standard library functions are used in either .c file and add the necessary #include at the top of main.c and program.c. For example, main.c uses fgets and program.c uses puts. So both should #include <stdio.h>.
I'll leave the rest for you as an exercise.
I want to create a hash table for an exercise I have to send in my University.
The program will open a number of files, break each file's content to <<words>> (tokens) and it will save each <<word>> in a hash table with the frequency of each <<word>>.
In case the word is already in the hash table , the program will increase the word's frequency.
At the end the program will print the words and it's frequencies accordingly.
Also the frequencies should be printed from the highest word frequency to the lowest.
The comparison of the <<words>> will ignore upper and lower case letters.
For example if a file contains : one two three four Two Three Four THREE FOUR FoUr
It should print:
four 4
three 3
two 2
one 1
The professor gave us a template that we should complete but I'm really confused on what to do with the insert_ht() and clear_ht() functions as well as the compare one.
Here is the code :
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#define HTABLE_SIZ 1001
#define MAX_LINE_SIZ 1024
/* Hash Table */
typedef struct node* link;
struct node { char *token; int freq; link next; };
link htable[HTABLE_SIZ] = { NULL }; /* Table of lists (#buckets) */
int size = 0; /* Size (number of elements) of hash table */
unsigned int hash (char *tok );
void insert_ht (char *data);
void clear_ht ( );
void print_ht ( );
void Process(FILE *fp);
int main(int argc, char *argv[])
{
int i;
FILE *fp;
for (i=1; i < argc; i++)
{
fp = fopen(argv[i],"r");
if (NULL == fp)
{
fprintf(stderr,"Problem opening file: %s\n",argv[i]);
continue;
}
Process(fp);
fclose(fp);
}
print_ht();
clear_ht();
return 0;
}
void Process(FILE *fp)
{
const char *seperators = " ?!'\";,.:+-*&%(){}[]<>\\\t\n";
char line[MAX_LINE_SIZ];
char *s;
while((fgets(line,MAX_LINE_SIZ, fp)) != NULL)
{
for (s=strtok(line,seperators); s; s=strtok(NULL,seperators))
insert_ht(s);
}
}
/* Hash Function */
unsigned int hash(char *tok)
{
unsigned int hv = 0;
while (*tok)
hv = (hv << 4) | toupper(*tok++);
return hv % HTABLE_SIZ;
}
void insert_ht(char *token)
{
……………………………………………
}
void clear_ht()
{
……………………………………………
}
int compare(const void *elem1, const void *elem2)
{
……………………………………………
}
void print_ht()
{
int i, j=0;
link l, *vector = (link*) malloc(sizeof(link)*size);
for (i=0; i < HTABLE_SIZ; i++)
for (l=htable[i]; l; l=l->next)
vector[j++] = l;
qsort(vector,size,sizeof(link),compare);
for (i=0; i < size; i++)
printf("%-50s\t%7d\n",vector[i]->token,vector[i]->freq);
free(vector);
}
I'll answer you in a new post because it's hard to be exhaustive in comments.
1. Malloc
Why would I need to use malloc then ? Shouldn't i write directly to the htable? (on the insert_ht() funtion)
You need to use malloc because you declare a char pointer in struct (char *token). The thing is that you never initialize the pointer to anything, and as far you don't know the size of the token, you need to malloc every token. But, as you use strdup(token), you don't need to malloc token because strdup does. So don't forget to free every token in order to avoid memory leaks.
2. Segfault
I can't test you code, but it seems like the following line causes the segmentation fault :
list = htable[hashval]->token
Indeed, you try to access token while htable[hashval] is NULL, and to assign a char * to a link type (list).
You need to loop with this :
for(list = htable[hashval]; list != NULL; list = list->next) { ... }
3. Notes
if (x=1) should be if(x==1).
Don't malloc new_list if you don't need to.
Because new_list if used when htable[hashval] is NULL, new_list->next = htable[hashval]; will set new_list->next to NULL.
You should use the -Wall option in gcc (for warnings) and you may use valgrind to understand your segmentation faults. In this case, use gcc with debug mode (-g).
Double and Final edit : Ι found the solution. Apparently for some reason my compare function was wrong.
I still haven't figured out why but here is the correct one, hopefully someone else will find this post helpful!
int compare(const void *elem1, const void *elem2)
{
return (*(link*)elem2)->freq - (*(link*)elem1)->freq;
}
Edit: deleted old answer . Found the correct way I think but I have another problem right now.
The compare function doesn't work correctly. My printf is fine but it doesnt sort them with the frequiencies. I want them to be sorted from the highest to lowest .
In this example: the file contains -> one two three four Two Three Four THREE FOUR FoUr
And I get:
two 2
one 1
four 4
three 3
While I should be getting :
four 4
three 3
two 2
one 1
Here is the code. Feel free to help!
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#define HTABLE_SIZ 1001
#define MAX_LINE_SIZ 1024
/* Hash Table */
typedef struct node* link;
struct node { char *token; int freq; link next; };
link htable[HTABLE_SIZ] = { NULL }; /* Table of lists (#buckets) */
int size = 0; /* Size (number of elements) of hash table */
unsigned int hash (char *tok );
void insert_ht (char *data);
void clear_ht ( );
void print_ht ( );
void Process(FILE *fp);
int main(int argc, char *argv[])
{
int i;
FILE *fp;
printf("prin tin for \n");
for (i=1; i < argc; i++)
{
printf("prin tin fopen \n");
fp = fopen(argv[i],"r");
if (NULL == fp)
{
fprintf(stderr,"Problem opening file: %s\n",argv[i]);
continue;
}
printf("prin tin process \n");
Process(fp);
fclose(fp);
}
print_ht();
//clear_ht();
return 0;
}
void Process(FILE *fp)
{
const char *seperators = " ?!'\";,.:+-*&%(){}[]<>\\\t\n";
char line[MAX_LINE_SIZ];
char *s;
while((fgets(line,MAX_LINE_SIZ, fp)) != NULL)
{
for (s=strtok(line,seperators); s; s=strtok(NULL,seperators)){
printf("prin tin insert %s \n",s);
insert_ht(s);
}
}
}
/* Hash Function */
unsigned int hash(char *tok)
{
printf("bike stin hash \n");
unsigned int hv = 0;
while (*tok)
hv = (hv << 4) | toupper(*tok++);
printf("VGAINEIIIIIIIIIIIIII %d \n",hv);
return hv % HTABLE_SIZ;
}
void insert_ht(char *token)
{
printf("bike stin insert %s \n",token);
unsigned int hashval = hash(token);
if (htable[hashval]==NULL){
printf("mesa stin prwti if %u %s \n",hashval,token);
//token = strdup(token);
htable[hashval] = malloc(sizeof(token));
htable[hashval]->token = token ;
htable[hashval]->freq = 1;
size++;
}else {
htable[hashval]->freq++;
}
printf("ta evale epitixws \n");
}
int compare(const void *elem1, const void *elem2)
{
const struct node *p1 = elem1;
const struct node *p2 = elem2;
if ( p1->freq < p2->freq)
return -1;
else if (p1->freq > p2->freq)
return 1;
else
return 0;
}
void print_ht()
{
int i, j=0;
link l, *vector = (link*) malloc(sizeof(link)*size);
for (i=0; i < HTABLE_SIZ; i++)
for (l=htable[i]; l; l=l->next)
vector[j++] = l;
qsort(vector,size,sizeof(link),compare);
for (i=0; i < size; i++)
printf("%-50s\t%7d\n",vector[i]->token,vector[i]->freq);
free(vector);
}
Sorry for my bad english.
I think that :
insert(char *token) takes a word of the file and puts into the hash table. In brief, if the word exists in the hash table, you just have to increment its frequencie. Otherwise, you need to create another node and put the frequencie to 1, then ad it to the array. At the end, you will have one entry for each unique word.
compare(const void *elem1, const void *elem2) will be used by qsort. It returns 0 if elem1 = elem2, a negative number if elem1 < elem2 and a number > 0 if elem1 > elem2. By passing compare to qsort, you allow qsort to sort you array according to your own criteria.
clear_ht() may set all the values of the array to NULL, in order to restart another count ?
I've encountered a problem trying to reduce the size of my code. What I was trying to do was passing either name or color to function writedata so that I wouldn't have to write it twice for each case.
typedef struct Pet{
char* name;
char* color;
} pet;
void writedata(pet *Pet, char string[], const char field[]){
gets(string);
Pet->field= (char*)malloc(strlen(string)+1);//I wanted it to be treated like Pet->name
strcpy(Pet->field, string);
}
The call of the function:
writedata(Pet, string, name);
I'm quite sure I got something wrong.
update: the whole code http://ideone.com/Y7L8Hu
update2: I tried to implement it using offset according to BLUEPIXY's advice but it seems I misunderstand manipulations with fields using their addresses... I believe the problem could be that the fields aren't initialized in the first place, but then again, my aim is to initialize them.
typedef struct Pet{
char* name;
int legs;
char* color;
} pet;
void writedata(pet *Pet, size_t FIELD){
char string[50];
gets(string);
(char*)Pet+offsetof(struct Pet, FIELD) = (char*)malloc(strlen(string)+1);//I wanted it to be treated like Pet->name
strcpy((char*)Pet+FIELD, string);
}
That's not how C works. However, I think using string comparison can achieve what you need:
if (strcmp(field, "name") == 0)
{
Pet->name = ...
}
else if (strcmp(field, "color") == 0)
{
Pet->color = ...
}
And call it with a string literal:
writedata(Pet, string, "name");
Using enum is also an option.
BTW, don't use gets, it's dangerous, use fgets instead.
use macro function sample.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define writedata(var, buffer, field) \
do {\
int len = strlen(buffer);\
var->field = (char*)malloc(len + 1);\
memcpy(var->field, buffer, len+1);\
}while(0)
typedef struct Pet{
char* name;
int legs;
char* color;
char* voice;
} pet;
void addpet(pet* Pet, int *TotalLegs){//Can not be used reference(&) in C
char buff[50];
int len;
puts("Input name");
scanf("%49[^\n]", buff);
writedata(Pet, buff, name);
puts("How many legs?");
scanf("%d%*c", &Pet->legs);
puts("What does it say?");
scanf("%49[^\n]%*c", buff);
writedata(Pet, buff, voice);
puts("_____\n");
*TotalLegs += Pet->legs;
}
int main(){
int TotalLegs = 0;
pet* Pet1 = (pet*)malloc(sizeof(pet));
addpet(Pet1, &TotalLegs);
pet* Pet2 = (pet*)malloc(sizeof(pet));
addpet(Pet2, &TotalLegs);
pet* Pet3 = (pet*)malloc(sizeof(pet));
addpet(Pet3, &TotalLegs);
//printf("%s\n", Pet1->name);
//printf("%s\n", Pet1->voice);
printf("The animals have %d legs\n", TotalLegs);
free(Pet1);free(Pet2);free(Pet3);
return 0;
}
A lot of things are wonky in your code.
What you wish to do can be achieved but it takes different type of code than you'd want to write.
What you really want to do is simply create a function that fills in a name and a color.
So here is the simplest way to do it:
typedef struct pet {
char *name;
char *color;
} pet_t;
pet_t * new_pet(const char *name, const char *color)
{
pet_t *p;
p = malloc(sizeof(pet_t));
if ( p == NULL )
return NULL;
p->name = strdup(name); /* allocate space and copy string */
p->color = strdup(color); /* allocate spance and copy string */
return p;
}
void delete_pet(pet_t *p)
{
if ( p-> name )
free(p);
if ( p->color)
free(color);
if ( p )
free(p);
}
int main() {
pet_t *p;
p = new_pet("Harry", "brown");
printf("%s is a %s pet\n", p->name, p->color);
delete_pet(p);
return 0;
}