Passing struct into function - c

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

Related

Is it possible to only send one variable from a struct if that struct exists as an array?

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.

Can't pass typedef struct to function by reference

I'm trying to pass a custom type object to a function by reference, and I can't figure out what I could be doing wrong. I read How do you pass a typedef struct to a function? as well as other references and could swear I'm already doing exactly that. I cleared out everything else I'm doing and even this spartan code throws 5 errors. Help me, Stackexchange; You're my only hope!
The goal is simply to be able to alter the values in the array in the object.
#include <stdio.h>
#include <math.h>
typedef struct structure {
char byte[10];
char mod;
} complex;
void simpleInit (complex *a, char value) {//put the value in the first byte and zero the rest
a.byte[0] = value;
char i;
for (i = 1; i < 10; ++i) {
a.byte[i] = 0;
}
a.mod = 1;
}
void main () {
complex myNumber;
char value = 6;
simpleInit (myNumber, value);
}
When I attempt to run this I get this error and 4 similar:
test2.c:10:3: error: request for member ‘byte’ in something not a structure or union
a.byte[0] = value;
a is a pointer type, so you need to de-reference it to use it. Typically that's done with the arrow operator:
a->byte[i] = 0;
Since this is just an array of bytes you can also quickly "zero" it:
memset(a, 0, 10);
Though given how important 10 is in your code you should codify that in a constant or a #define.
When you pass a value by reference you need to use asterisk to access al fields of the structure, for example:
(*a).byte[0] = value;
Happily you have -> as a shortcut, so this will be:
a->byte[0] = value;
Also do not forget to call the & (address of) operator when you call simpleInit.
#include <stdio.h>
#include <math.h>
typedef struct structure
{
char byte[10];
char mod;
} complex;
void simpleInit (complex *a, char value)
{
char i;
a->byte[0] = value;
for (i = 1; i < 10; ++i) {
a->byte[i] = 0;
}
a->mod = 1;
}
int main()
{
complex myNumber;
char value = 6;
simpleInit (&myNumber, value);
}

Sending array of structures to function

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.

creating, passing, getting back Array of a Struct and loop throuh it in C

I need to execute a function that returns array of a specified struct with variable length. Then I should loop through the returned array.
example struct :
typedef struct student {
int id;
char *name;
int grade;
} Student;
function prototypes 1 :
Student *students;
students = findStudentByGrade(int grade);
function prototypes 2 :
Student *students;
int retval = findStudentByGrade(&students, int grade);
I am bit confused on above methods. How can correctly define a array of struct? call function ? and loop through it untill end? Can some one help me please.
You can do this in this way. This code is working. I tested in CodeLite.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct student {
int id;
char *name;
} Student;
Student *findStudent(int *asize, const int grade);
int main(void)
{
Student *stds;
int asize = 0;
stds = findStudent(&asize, 5);
int i;
for (i = 0; i < asize; i++) {
printf("ID : %i\n", stds[i].id);
}
return 0;
}
Student *findStudent(int *asize, const int grade)
{
struct student *stds = malloc(sizeof(struct student) * 3);
stds[0].id = 10;
stds[1].id = 20;
stds[2].id = 40;
*asize = 3;
return stds;
}
Get the array of struc as returned statement and pass an int variable with argument list to get the size back and simply loop through using a for loop. Or else you will find problem in looping. It is more easy to get the array size from the function which create the array.
I mean this is quite a basic question, but:
Defining array of your structures would look like:
int size = ...;
Student *students = (Student*) malloc(sizeof(Student) * size);
Then just pass that to the function (both size and the array) and then just loop until i < size.
Ofcourse, don't forget to:
free(students);
at the end.

how to write the character value from structure into the serial interface and convert into integer value?

struct MemoryTag1;
typedef struct MemoryTag1{
char a[8]= {'+','0','2','6','.','5','EA','\r'}; // setpoint temperature value
char b[8]= {'-','0','2','4','.','5','EB','\r'};
char c[6]= {'+','0','2','0','EC','\r'};
}Memory1;
// This is a message structure which I want to transfer over the serial interface (RS232) and later convert into integer value. please guide me in this.
Your syntax is a bit off - try this:
// declare Memory1 struct type to hold data
typedef struct MemoryTag1 {
char a[9]; // setpoint temperature value
char b[9];
char c[7];
} Memory1;
// allocate and initialise a Memory1 struct
Memory1 m = { {'+','0','2','6','.','5','E','A','\r'},
{'-','0','2','4','.','5','E','B','\r'},
{'+','0','2','0','E','C','\r'} };
Really, to be honest, I'd prefer more information. But it doesn't really matter. It only affects the method of output. If you were running this on an arduino, for instance, you could output to the serial ports as easily as:
Serial.begin(9600);
Serial.write('a');
etc, etc
As others have mentioned, there are situations in which you'd be better off using null-terminated strings. If however, you had a particular reason to do so, then I suppose you could;
#include <stdio.h>
typedef struct memoryTag1_t
{
char a[9]; // setpoint temperature value
char b[9];
char c[7];
} *pMemoryTag1_t;
typedef struct memoryTag2_t
{
char a[10]; // setpoint temperature value
char b[10];
char c[8];
} *pMemoryTag2_t;
void displayField1(char *field, int len)
{
for (int i=0; i<len; i++)
{
if (i!=0) printf(",");
printf("%c", field[i]);
}printf("\n");
}
void displayField2(char *field)
{
bool firstDone = false;
while (*field)
{
if (firstDone)
printf(",");
else
firstDone = true;
printf("%c", *field++);
}
printf("\n");
}
int main()
{
memoryTag1_t myMem1 =
{
{'+','0','2','6','.','5','E','A','\r'},
{'-','0','2','4','.','5','E','B','\r'},
{'+','0','2','0','E','C','\r'}
};
memoryTag2_t myMem2 =
{
"+026.5EA\r",
"-024.5EB\r",
"+020EC\r"
};
displayField1(myMem1.a, sizeof(myMem1.a));
displayField1(myMem1.b, sizeof(myMem1.b));
displayField1(myMem1.c, sizeof(myMem1.c));
displayField2(myMem2.a);
displayField2(myMem2.b);
displayField2(myMem2.c);
}
Output:
(Don't forget there's a \r printed 'after' the last comma in each line)
+,0,2,6,.,5,E,A,
-,0,2,4,.,5,E,B,
+,0,2,0,E,C,
+,0,2,6,.,5,E,A,
-,0,2,4,.,5,E,B,
+,0,2,0,E,C,
you can not declare struct in C in this way:
it should be
typedef struct MemoryTag1{
char a[9];
char b[9];
char c[7];
}Memory1;
you can set value in the declaration of an object of this structure:
Memory1 test = {
{'+','0','2','6','.','5','E','A','\r'},
{'-','0','2','4','.','5','E','B','\r'},
{'+','0','2','0','E','C','\r'}
};
If you use this bloc in each initiation of a Memory1 object so you can use macro to make it easier:
#define INIT_MEMORYTAG1 {\
{'+','0','2','6','.','5','E','A','\r'},\
{'-','0','2','4','.','5','E','B','\r'},\
{'+','0','2','0','EC','\r'}\
}
and then in your declaration of a Memory1 object:
Memory1 test = INIT_MEMORYTAG1;
BTW: You can not put 'EA', 'EB', 'EC' like a 1 charachter you have to separate them to:
'E','A', 'E','B', 'E','C' and so you have to update your char array sizes in the struct definition
That is really not C syntax.
You can't have initializers in declarations of types, that doesn't have any meaning.
You need to do it like this, to build the message:
typedef struct {
char a[10];
char b[10];
char c[8];
} Memory1;
int main(void)
{
Memory1 m1;
strcpy(m1.a, "+026.5EA\r");
strcpy(m1.b, "-024.5EB\r");
strcpy(m1.c, "+020EC\r");
return 0;
}
Note that the above will build proper C strings in the fields of the message, i.e. there will be 0-characters acting as terminators. The sizes were too small, so I changed that.
It's trivial to ignore the terminator characters if you need to send this over some format that doesn't allow them; send each field separately.
Converting one of the fields back into integers could be done using sscanf(), for instance.

Resources