I'm new in C and would love to get some help regarding multipule input
for example I have this struct:
typedef struct person{
char * name;
int age;
}
and I want to write a function that get's :name age name age name age...
Is there a way I can do that ? how can I later get the values?
I mean something like :
void my_func(char* name, int age , char* name1,int age1.....)
like in JAVA I can use "..."
I want to do something like that :
void my_func(char* name, int age , char* name1,int age1.....){
int num_of_ppl = length of the input/2
person p1 ;
p1.name = first input name
p1.age = first input age
etc..
thanks!
You can use the vararg functionality in stdarg.h:
//
// First argument specifies the number of name/age pairs supplied
//
void my_func(int persons, char *name1, int age1, ...) {
int age, i;
char *name;
va_list vl;
va_start(vl, age1);
for (i = 1; i < persons; i++) {
name = va_arg(vl, char*);
age = va_arg(vl, int);
// Do something with the values
}
va_end(vl);
}
If you want a function with variable argument list you can use va_list
#include <cstdarg>
using namespace std;
void myFunction(int num, ...)
{
va_list arguments; // A place to store the list of arguments
va_start ( arguments, num ); // Initializing arguments to store all values after num
for ( int x = 0; x < num; x++ ) // Loop until all numbers are added
func(va_arg ( arguments, person )); // get next value of argument and call a function
va_end ( arguments ); // Cleans up the list
}
The C language is a very low-level language, so you'll need to decide how to handle each field.
In your case you need to decide what is the name, who owns the pointed data, and code appropriately, perhaps something like:
typedef struct person_st {
char* name; // malloc-ed string
int age;
} Person;
// allocate a Person of given name and age
Person* make_person(const char* n, int a) {
if (!n || a<0) return NULL;
Person* p = malloc(sizeof(Person));
if (!p)
perror("malloc Person"), exit(1);
p->name = strdup(n);
if (!p->name)
perror("strdup Person"), exit(1);
p->age = a;
return p;
}
// destroy a Person and the data inside
void destroy_person(Person*p) {
if (!p) return;
free (p->name);
free (p);
}
// read and allocate a Person
Person* input_person(FILE*f) {
if (!f) return NULL;
char name[104];
int age;
memset (name, 0, sizeof(name));
age = 0;
if (fscanf(f, " %100[A-Za-z] %d", &name, &age)<2)
return NULL;
return make_person(name, age);
}
with the convention that the caller of input_person should call destroy_person appropriately.
I might have misunderstood your question. Do you want to code simply a variadic function (which has no relation to input or output)? Then use carefully <stdarg.h> header. Be aware that variadic functions are poorly typed in C. With GCC, you can give the sentinel function attribute, and you could even customize GCC e.g. with MELT to add some type checking.
Related
I have a struct of pointers and a global pointer to use in functions declared after main. Now declaring the functions with those same name of pointers is fine. But when I call it within another function (because its like a menu type program), I kept getting different types of errors.. Like expression is needed, unexpected type, etc. My question is simply how to I call the parameters for the function to work. I haven't used C in years so the solution might seem simpler than it sounds like. The code below will show you what I mean.
StudentPtr studentArray
StudentPtr** studentArray
struct StudentPtr *studentArray
*StudentPtr studentArray[]
(Pretty much moving the pointers around and using struct as prefix)
typedef struct Student {
char *firstName;
char *lastName;
char *id;
char *email;
} Student, *StudentPtr;
//Prototypes:
int fillData(StudentPtr studentArray,char* f, char* l, char* id, char* e,int n);
int displayData(StudentPtr studentArray, int n);
int displayDataAll(StudentPtr studentArray);
int main()
{
return 0;
}
int command(char line[])
{
//other code here
//some more code..
//......
//error below
if(lineSize==0) /* If the command is empty, asks again for a command */
{
return 0;
}
else
{
if(strncmp(line,"1",lineSize)==0)
{reset();}
else if(strncmp(line,"2",lineSize)==0)
{fillData(StudentPtr studentArray,char* f, char* l, char* id, char* e,int n);} //the first parameter here
else if (strncmp(line,"3",lineSize)==0)
{modify(StudentPtr studentArray,char* f, char* l, char* id, char* e,int n);} //here as well
else if(strncmp(line,"4",lineSize)==0)
{displayDataAll(StudentPtr studentArray);} //here too
else if(strncmp(line,"5",lineSize)==0)
{return 1;}
else
{noComm();}
}
return 0;
}
//example of the functions supposed to be used
int fillData(StudentPtr studentArray,char* f, char* l, char* id, char* e,int n)
{
//get the start of the nth record
//Ptr arithmetic
StudentPtr currentStudentptr = studentArray+(n-1);
//allocate memory for the character pointers
currentStudentptr->firstName =malloc(sizeof(char)*20);
strcpy(currentStudentptr->firstName,f);
//... same for others
return 0;
}
The calling of the function here should properly call the functions that are further down.
You are mixing syntax for function declaration and definition with syntax for calling a function:
{fillData(StudentPtr studentArray,char* f, char* l, char* id, char* e,int n);} //the first parameter here
In a function call you mustn't specify the type. You only provide the arguments:
{fillData(studentArray, f, l, id, e, n);}
You do not show any variable definiton. Therefore I cannot tell if the variables have correct types or if you need to add some & operators here and there...
That is the reason why a minimum complete verifyable example is mandatory.
I apologise if this seems simple, I'm still learning and I'm new to C.
I have this as my struct:
struct Game{
char id;
char name[50];
char genre[20];
char platform[15];
char company[30];
float price;
int quantity = 10;
};
And this declared as a struct array:
struct Game gList[30];
I have a function where I'm passing all of 'gList' to search through values in the gList[i].name variables.
So my question is, is it possible to send only the gList[i].name part of the struct to the function as a parameter?(ie All the 30 name values only).
No.
But you could make an array of pointers that point to the name field and pass it to the function:
char* ptr[30];
for(int i = 0; i < 30; i++)
ptr[i] = gList[i].name;
func(ptr);
No you can't. However, you can pass iterators to functions just fine. Typical pattern:
struct context { struct Game *gList; int nList; int i; }
char *iter_names(void *baton)
{
struct context *ptr = baton;
if (ptr->i == ptr->nList) return NULL;
return ptr->gList[ptr->i++].name;
}
void wants_name_array(char (*nextname)(void *), void *baton)
{
while (char *name = nextname(baton))
{
printf("%s\n", name);
/* and whatever else you are doing */
}
}
/* ... */
struct context baton = { gList, 30, 0 };
wants_name_array(iter_names, baton);
Yeah it looks kinda bad. Thankfully, gcc has an extension that makes this much better.
void wants_name_array(char (*nextname)())
{
while (char *name = nextname())
{
printf("%s\n", name);
/* and whatever else you are doing */
}
}
/* ... */
{
int i = 0;
char *nextname()
{
if (i == 30) return NULL;
return gList[i++].name;
}
wants_name_array(nextname);
}
When using this particular gcc extension, never ever return nested functions. Undefined behavior.
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;
}
in order to complete a larger project, im trying to get an idea of how to send an array of structures, and a token of char* type to a function. my Pupose of this code is to do the following:
open file
tokenize file
send token,and array of structures to search function
search function will go through the arrayofstructures, using strcmp to find a match with token
if match found return 1, the main function will check for 1 or 0
if 0, dont add token to array of structures,if 1 add token to arrayof structures
i just wrote a small program to see if i could send the array,and token to a function and compare but i get so many errors im lost at what to do since i dont understand most of the errors.
#include <stdio.h>
#include <string.h>
int search(struct id array[],char* tok);
struct id
{
char name[20];
int age;
};
int main(void)
{
struct id person[2] = { {"John Smith", 25},
{"Mary Jones", 32} };
char* token = "Mary Jones"; /*char* for strtok() return type*/
search(person,token);
}
int search(struct id array[],char* tok)
{
int i,value;int size = 2;
for(i=0;i<size;i++)
{
if(strcmp(array[i].name,tok) == 0)
value = 0;
else
value = 1;
}
return value;
}
Place
int search(struct id array[],char* tok);
after struct declaration. And assign the return value from search to an int variable.
int found = search(person,token);
if(found == 0)
printf("Name is found\n"); // or whatever you want
Here is the code that you should use.
#include <stdio.h>
#include <string.h>
struct id
{
char name[20];
int age;
};
int search( const struct id array[], size_t n, const char *tok );
int main( void )
{
struct id person[2] = { {"John Smith", 25},
{"Mary Jones", 32} };
char* token = "Mary Jones"; /*char* for strtok() return type*/
printf( "%d\n", search( person, sizeof( person ) / sizeof( *person ), token ) );
return 0;
}
int search( const struct id array[], size_t n, const char *tok )
{
size_t i = 0;
while ( i < n && strcmp( array[i].name, tok ) != 0 ) ++i;
return n != 0 && i != n;
}
EDIT: I removed some typos.
The output is
1
that is the name has been found.
Take into account that the correct function search has to return 1 if the name is found.:)
Always declare structs / enums / unions before defining pointers to them, or using them in a function declaration, like this:
struct id;
Extra tip, introduce a typedef-name with the same id as the tag name at the same time:
typedef struct id id;
Always declare functions before first use, like this:
int search(struct id array[],char* tok);
Always define structs / enums / unions before using them for anything but what the first rule covers, like this:
struct id {
char name[20];
int age;
};
With typedef-name:
typedef struct id { /**/ } id;
Now, where possible, put the definition where you would otherwise need to put a forward-declaration.
Only exception: If you put the declaration in a header-file, that's fine.
That reduces superfluous redundancy.
Some more observations:
Don't use fixed-size fields for names and such. They are always too short.
Never modify string literals, failing to heed that prohibition results in Undefined Behavior, your program just became meaningless. Work with a copy instead.
/* Most implementations supply this non-standard function */
char* strdup(const char* s) {
size_t n = strlen(s)+1;
char* p = malloc(n);
if(p) memcpy(p, s, n);
return p;
}
When you pass an array, you are actually only passing a pointer to its first element, so pass an element-count too.
Types size_t or ssize_t are designed for that chore.
If you have an array named a, you get the element count using sizeof a / sizeof *a. Be sure that's not a pointer though!
Early return are good: Return success as early as possible.
Then you don't chance to forget your success in the next loop iteration (as happened to you), beside being faster.
Hi guys i've got a problem here with structs, the thing is, i've created a struct and then created a function that captures the employee details referenced from that struct. Now the problem comes when i try to call the function in the main. please give me some pointers as to how to call the function. the code is as follows:
typedef struct employeeType
{
char name;
int employeeNumber;
float salary;
float taxPercentage;
}EMPLOYEE;
void enterDetails(EMPLOYEE details)
{
FILE *file;
file = fopen("employees.txt","w");
if(file == NULL)
{
printf("File error!!!");
exit(0);
}
else
{
fprintf(file,"%s",details);
}
fclose(file);
}
void main()
{
enterDetails();
}
I don't know what parameters to pass to the function in the main
I've annotated your code with some other issues to consider
typedef struct employeeType
{
/* THIS IS ONLY ONE CHARACTER... SEEMS WRONG */
/* should be 'char name[someMaxSize]', or 'char *name' */
char name;
int employeeNumber;
float salary;
float taxPercentage;
}EMPLOYEE;
/* As pointed out by 'Cody Gray', this function is called 'enterDetails'
* does it really need to have a parameter at all, or should it be responsible
* for taking the details from the user? Is it an appropriately
* named method for the task it's actually performing
* (would saveDetails be better for example)?
*/
void enterDetails(EMPLOYEE details)
{
FILE *file;
file = fopen("employees.txt","w");
if(file == NULL)
{
printf("File error!!!");
exit(0);
}
else
{
/* THIS IS PASSING A STRUCTURE AS A STRING */
/* You probably want to write out the individual fields instead */
/* fprintf(file, "%s,%d", details.name, details.employeeNumber); etc */
fprintf(file,"%s",details);
}
fclose(file);
}
void main()
{
EMPLOYEE details;
/* populate details somehow then pass it in to the function*/
enterDetails(details);
}
You may also want to consider passing details into the function as a pointer, although that would change your function signature, it would mean that you're not pushing as much information onto the stack.
If you go with the pointer version then:
void enterDetails(EMPLOYEE details)
would become
void enterDetails(EMPLOYEE *details)
and the main would become:
void main()
{
EMPLOYEE details;
/* populate details somehow then pass it in to the function as pointer */
enterDetails(&details);
}
You would also need to change the way you use details within your function, but as I've already said, I believe your fprintf call is broken already.
You can pass the pointer of the struct
void main()
{
EMPLOYEE employee;
.....
enterDetails(&employee);
}
void enterDetails(EMPLOYEE *details)
{
}
You need to pass a reference, not a value... If you pass EMPLOYEE value as in the previous post, it will be copied, the copy will be modified, not the original
void enterDetails(EMPLOYEE* emp) {
// do stuffs
}
void main() {
EMPLOYEE emp;
enterDetails(&emp);
}
void main()
{
EMPLOYEE details;
// get the value of element of struct from scanf or from other way
printf("Enter Name : ");
scanf("%s", details.name); // same for others, change the format specifier according to their data type
enterDetails(details);
}
And struct should be like
typedef struct employeeType
{
char name[]; // should be an array or pointer, to store name
int employeeNumber;
float salary;
float taxPercentage;
}EMPLOYEE;
The first problem is that your structure isn't correct. You can't store the employee's name on the name field since it's only one byte. You have to make it an array (it's simpler on this case) or a pointer to allocated memory.
If you want to make it an array, then you should define the maximum size of the array. In our example we will just make it 100 bytes, it will be more than enough to store any name.
#define MAX_NAME 100
typedef struct employeeType
{
char name[MAX_NAME];
int employeeNumber;
float salary;
float taxPercentage;
}EMPLOYEE;
Second, you're function naming is confusing. enterDetails should just populate the structure you passed. Third, your enter Details should accept a pointer to the EMPLOYEE structure. If you want to pass any value to a function that's going to change it's content, then you can only do that using pointers (or references if you're using C++ but that's basically a pointer). So enterDetails should be,
void enterDetails(EMPLOYEE *details)
{
printf("\nEnter the employee's name ");
scanf("%s", details->name); // this isn't secure since it doesn't perform bound checking.
printf("\nEnter employee number ");
scanf("%d", &details->employeeNumber);
printf("\nEnter employee salary ");
scanf("%f", &details->salary);
printf("\nEnter tax percentage ");
scanf("%f", &details->taxPercentage);
}
And finally, if you want to store the contents of the structure to a file that you want humans to read, then you should format the contents of the structure and dump it onto a file.
int writeToFile(EMPLOYEE *details) /* accepting the structure will work as well but it's faster and efficient to pass the structure's pointer */
{
FILE *file;
file = fopen("employees.txt","w");
if(file == NULL) {
printf("File error!!!");
return 0;
}
fprintf(file, "\nEmployee Name: %s", details->name);
fprintf(file, "\nEmployee Number: %d", details->employeeNumber);
fprintf(file, "\nSalary: %f", details->salary);
fprintf(file, "\nTax Percentage: %f", details->taxPercentage);
fclose(file)
return 1;
}
And main
int main(void)
{
EMPLOYEE details;
enterDetails(&details); // passing the pointer here is a must
if (!writeToFile(&details)) { // passing the pointer since it's faster
printf("\nError writing to file");
return 1;
} else {
printf("\nSuccess!");
return 0;
}
}
And in your case, you don't need to pass any parameters to main. But if you want to know how to pass parameters, then here is a quick example.
int main(int argc, char **argv)
{
int i;
for (i = 0; i < argc; i++)
printf("\n%s", argv[i]);
return 0;
}