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.
Related
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 100000
typedef struct {
int day;
int month;
int year;
} DATE;
typedef struct {
char name[100];
int age;
float hrlyWage;
float hrsWorked;
float regPay;
float otPay;
float totalPay;
DATE payDate;
} PAYRECORD;
int newRecord(struct PAYRECORD record[], int index){
//set name to \0 so it can work as string
record[index].name = {'\0'};
index++;
return index;
}
int main(){
char menuChoice = 'X';
struct PAYRECORD record[SIZE];
int index = 0;
while (menuChoice != 'Q'){
system("pause");
system("cls");
menuChoice = runMenu();
switch (menuChoice){
case 'A':
index = newRecord(record, index);
}
}
}
main sets up an array of structs the gets passed into newRecord, and the goal is to make it so that I can input the data here and then return the new index to keep track of my array of structs. However something is going wrong where my program doesn't seem to be recognizing newRecord as a function, which ends up throwing the whole program off.
I get syntax errors for all the functions inside of newRecord, though I beleive it's because, as I mentioned, the program seems to be unable to recognize newRecord as a User defined Function.
Use of struct PAYRECORD is wrong since there is no such type. You only have a typedef named PAYRECORD.
If you want to be able to use struct PAYRECORD as well as just PAYRECORD, change the definition of the struct to:
typedef struct PAYRECORD {
char name[100];
int age;
float hrlyWage;
float hrsWorked;
float regPay;
float otPay;
float totalPay;
DATE payDate;
} PAYRECORD;
If that's not your goal, change the use of struct PAYRECORD by just PAYRECORD.
Also, the line:
record[index].name = {'\0'};
in newRecord is not correct. You cannot assign to an array like that. Change it to:
record[index].name[0] = '\0';
The struct PAYRECORD does not exist, the compiler has no idea how big that is.
Note that PAYRECORD is a typedef to an anonymous struct. So your function
should look like this:
int newRecord(PAYRECORD record[], int index){
//set name to \0 so it can work as string
record[index].name[0] = 0;
index++;
return index;
}
Also note that {'\0'}; works only when initializing a array when you declare
it:
char arr1[10] = { '\0' }; // OK
char arr2[10];
arr2 = { '\0' }; // NOT OK
// error: expected expression before ‘{’ token
// a = { '\0' };
// ^
And when writing functions that take arrays as an argument, you should also pass
the size of the array.
int newRecord(PAYRECORD record[], int index, size_t len){
if(record == NULL)
return -1; // error, NULL passed
if(index >= len)
return -1; // error, cannot access array
record[index].name[0] = 0;
index++;
return index;
}
And then you can call it from main like this:
PAYRECORD record[SIZE];
...
int index = 0;
if(newRecord(record, index, sizeof record / sizeof *record) != index)
{
// error handling
}
This makes the code more robust. You always have to check the array boundaries,
otherwise you might read/write out of bounds. And also check that NULL has not
been passed as well, if you dereference NULL, your program will crash with
segfault.
Also, the parameter to newRecord could be a PAYARRAY, not an array directly; based on declaring
typedef struct { } PAYRECORD, PAYARRAY[SIZE];
int newRecord(PAYARRAY record, int index) {...}
int main(){
...
PAYARRAY record;
...
case 'A':
index = newRecord(&record, index);
}
The compiler should be converting the PAYARRAY or PAYRECORD[] argument to a PAYRECORD * pointing to the first element, so use of the '&' is indicated for the function call.
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;
}
I'm a newbie with C language and I need to make a function to sort an array of struct Student data types (after the element Student.ime alphabetically). I am not really sure where to put the pointers so I can return the new array.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Student {
int id;
char ime[20];
char prezime[20];
char brindexa[20];
struct Datum datum_rodjenja;
};
struct Student sortiraj(struct Student niz[], int vel)
{
int i, j;
struct Student tempo;
tempo = niz[0];
for(j=0 ; j<vel ; j++)
{
for(i=j ; i<vel ; i++)
{
if(strcmp(tempo.ime,niz[i].ime)>0)
{
tempo = niz[i];
}
i++;
}
niz[j] = tempo;
j++;
}
return niz;
}
The array is stored in a .txt file but that is not the problem. One more thing, how do I call the function in the main(). I thought maybe like this?
niz=sortiraj(niz, vel);
Can someone give me any tips please. Thank you.
You seem to be sorting the array in-place, so you don't really need to return it at all. Also, use the standard library function qsort():
int cmp(const void *ap, const void *bp)
{
const struct Student *a = ap, *b = bp;
return strcmp(a->ime, b->ime);
}
struct Student students[] = { /* whatever */ };
qsort(
students,
sizeof(students) / sizeof(studends[0]),
sizeof(students[0]),
cmp
);
Also, please use English function and variable names.
Have you considered using the qsort() function? Example:
If you have an array of strings say strings, (Note: not an array of structs), with the number of strings being say, cnt then:
qsort(strings, cnt, sizeof(char*), sortstring);
With the function sortstring defined as:
static int sortstring( const void *str1, const void *str2 )
{
const char *rec1 = *(const char**)str1;
const char *rec2 = *(const char**)str2;
int val = strcmp(rec1, rec2);
return val;
}
//for a simple test, run this main with the code above:
int main(void)
{
char *strings[]={"this", "is", "a", "test", "of", "the", "qsort", "function", "to", "try"};
int strlen = sizeof(strings)/sizeof(char *);
qsort(strings, strlen, sizeof(char *), sortstring);
return 0;
}
//Note my environment required #include <ansi_c.h>
First of all, your function signature is not marked return type as an Array of Students. Second of all, I don't know which sorting algorithm you're trying to use, but your implementation isn't right.
If you correct your function signature, you shouldn't get any error by the way you're calling the:
struct Student* sortiraj(struct Student niz[], int vel)
tips about your sortiraj: Check either selection sort or bubble sort for your sort algorithm. And for further study, you can check some recursive algorithms like merge sort and quick sort which are more advance and you need more programming knowledge to implement them.
Change the return type of function sortiraj to void.
Create and fill the struct Student niz[] array in function main.
From function main, pass the array and its length (vel) to function sortiraj.
And of course, no need to return anything from function sortiraj (as implied in section 1).
Since you are passing in a pointer, namely niz, you are changing the memory that niz points to. This means that you don't have to return niz.
However if you want to return niz your function's return type must be the same type as niz. Currently you have a return type of just struct Student so you should be getting a compilation error.
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.
This question already has answers here:
How do I return multiple values from a function in C?
(8 answers)
Closed 3 years ago.
Can anyone tell me how to return multiple values from a function?
Please elaborate with some example?
Your choices here are to either return a struct with elements of your liking, or make the function to handle the arguments with pointers.
/* method 1 */
struct Bar{
int x;
int y;
};
struct Bar funct();
struct Bar funct(){
struct Bar result;
result.x = 1;
result.y = 2;
return result;
}
/* method 2 */
void funct2(int *x, int *y);
void funct2(int *x, int *y){
/* dereferencing and setting */
*x = 1;
*y = 2;
}
int main(int argc, char* argv[]) {
struct Bar dunno = funct();
int x,y;
funct2(&x, &y);
// dunno.x == x
// dunno.y == y
return 0;
}
You can't do that directly. Your options are to wrap multiple values into a struct, or to pass them in as pointer arguments to the function.
e.g.
typedef struct blah
{
int a;
float b;
} blah_t;
blah_t my_func()
{
blah_t blah;
blah.a = 1;
blah.b = 2.0f;
return blah;
}
or:
void my_func(int *p_a, float *p_b)
{
*p_a = 1;
*p_b = 2.0f;
}
First of all, take a step back and ask why you need to return multiple values. If those values aren't somehow related to each other (either functionally or operationally), then you need to stop and rethink what you're doing.
If the various data items are part of a larger, composite data type (such as a mailing address, or a line item in a sales order, or some other type described by multiple attributes), then define a struct type to represent a single value of that composite type:
struct addr { // struct type to represent mailing address
char *name;
int streetNumber;
char *streetName;
char *unitNumber;
char *city;
char state[3];
int ZIP;
};
struct addr getAddressFor(char *name) {...}
struct point2D {
int x;
int y;
};
struct polygon2D {
size_t numPoints;
struct point2D *points;
};
struct point2D getOrigin(struct polygon2D poly) {...}
Do not define a struct to collect random items that aren't somehow related to each other; that's just going to cause confusion for you and anyone who has to maintain your code down the road.
If the data items are not functionally related, but are somehow operationally related (e.g. data plus a status flag plus metadata about the operation or items as part of a single input operation), then use multiple writable parameters. The most obvious examples are the *scanf() functions in the standard library. There are also the strtod() and strtol() functions, which convert a string representation of a number; they return the converted value, but they also write the first character that was not converted to a separate parameter:
char *str = "3.14159";
double value;
char *chk;
value = strtod(str, &chk);
if (!isspace(*chk) && *chk != 0)
printf("Non-numeric character found in %s\n", str);
You can combine these approaches; here's an example inspired by some work I'm currently doing:
typedef enum {SUCCESS, REQ_GARBLED, NO_DATA_OF_TYPE, EMPTY, ERROR} Status;
typedef struct bounds {...} Bounds;
tyepdef struct metadata {
size_t bytesRead;
size_t elementsRead;
size_t rows;
size_t cols;
} Metadata;
typedef struct elevations {
size_t numValues;
short *elevations;
} Elevations;
Elevations elevs;
Metadata meta;
Bounds b = ...; // set up search boundary
Status stat = getElevationsFor(b, &elevs, &meta);
The service that I request elevation data from returns a 1-d sequence of values; the dimensions of the array are returned as part of the metadata.
You can do it using structures:
#include <stdio.h>
struct dont { int x; double y; };
struct dont fred(void)
{
struct dont b;
b.x = 1;
b.y = 91.99919;
return b;
}
int main(int argc, char **argv)
{
struct dont look = fred();
printf("look.x = %d, look.y = %lf\n", look.x, look.y);
return 0;
}
You cannot return multiple values from a C function.
You can either
Return a data structure with multiple values, like a struct or an array.
Pass pointers to the function and modify the values of the pointers inside the function. You need to pass x number of pointers where x is the number of return values you need
To return multiple values from a function we should use a pointer. Here is an example through which you can understand it better
int* twoSum(int* nums, int numsSize, int target) {
int i,j,*a;
a=(int*)malloc(2*sizeof(int));
for(i=0;i<numsSize;i++)
for(j=i+1;j<numsSize;j++)
if(nums[i]+nums[j]==target)
{
a[0]=i;
a[1]=j;
return a;
}
}
I´m a beginner in C, so I don´t have experience with array, pointer, structure. To get more than one value from my function I just used a global variable.
Here is my code:
#include <stdio.h>
double calculateCharges( double hourCharges );
// Global variable for totalCharges-function and main-function interaction
double totalCharges = 0;
int main ( void ) {
double car1 = 0;
double car2 = 0;
double car3 = 0;
double totalHours = 0;
printf( "%s", "Hours parked for Car #1: ");
scanf( "%lf", &car1 );
printf( "%s", "Hours parked for Car #2: ");
scanf( "%lf", &car2 );
printf( "%s", "Hours parked for Car #3: ");
scanf( "%lf", &car3 );
totalHours = car1 + car2 + car3;
printf( "%s", "Car\tHours\tCharge\n");
printf( "#1\t%.1f\t%.2f\n", car1, calculateCharges( car1 ));
printf( "#2\t%.1f\t%.2f\n", car2, calculateCharges( car2 ));
printf( "#3\t%.1f\t%.2f\n", car3, calculateCharges( car3 ));
printf( "TOTAL\t%.1f\t%.2f\n", totalHours, totalCharges);
}
double calculateCharges( double hourCharges ) {
double charges = 0;
if( hourCharges <= 3.0 ) {
charges = 2;
} else if ( hourCharges >= 24.0) {
charges = 10.00;
} else {
charges = ((hourCharges - 3.0)*0.5) + 2.0;
}
totalCharges += charges;
return charges;
}
Method 1 is using array
Method 2 is using pointer
Method 3 is using structure