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
Related
I need to pass to qsort a generic array. That array must be taken from the colons of a file structured like this:
int,string,int,float.
I've created an appropriate struct type but I'm having troubles creating a dinamically allocated array of structures.
here I created an array of pointers to structures
struct *p_structure=malloc(n_records*sizeof(struct record_type*));
and then I have no idea on what to do :(
Any help would be really appreciated, thanks
PS I calculated the n_records in advance
I've created an appropriate struct type but I'm having troubles creating a dinamically allocated array of structures.
Assuming this is your struct:
struct record {
int i1;
char *s;
int i2;
float f;
};
This should be the array declaration:
struct record *array = malloc(sizeof(*array) * n_records);
and then I have no idea on what to do
In case you didn't do it already, you need to parse the file (see Appendix).
Once parsed, you have to define how your array items should compare against each another. In other words, what are the criteria that should be taken into consideration to compare (and of course, sort) your items. Programmatically, you need to provide a function that does that. That function's signature must match the signature of the function that qsort accepts as argument. For example (considering i1 as the comparison criteria):
int compare_record(const void *p1, const void *p2)
{
const struct record *r1 = p1;
const struct record *r2 = p2;
if (r1->i1 > r2->i1)
return 1;
if (r1->i1 < r2->i1)
return -1;
return 0;
}
Now, calling qsort becomes straightforward:
qsort(array, n_records, sizeof(*array), compare_record);
Appendix
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct record {
int i1;
char *s;
int i2;
float f;
};
int compare_record(const void *p1, const void *p2)
{
const struct record *r1 = p1;
const struct record *r2 = p2;
if (r1->i1 > r2->i1)
return 1;
if (r1->i1 < r2->i1)
return -1;
return 0;
}
int main(void)
{
int n_records = 3;
FILE *file = fopen("filename.txt", "r");
if (!file) {
printf("Opening file failed.\n");
exit(EXIT_FAILURE);
}
struct record *array = malloc(sizeof(*array) * n_records);
if (!array) {
printf("An internal error has occurred.\n");
exit(EXIT_FAILURE);
}
int index = 0;
char line[1024]; // Large enough to hold a line?
int i1, i2;
float f;
char s[256];
while (fgets(line, sizeof line, file)) { // PS I calculated the n_records in advance
if (sscanf(line, "%d,%255[^\n,],%d,%f", &i1, s, &i2, &f) != 4) {
// Problematic line...
printf("Problematic line %d...\n", index+1);
}
array[index].i1 = i1;
array[index].s = strdup(s);
array[index].i2 = i2;
array[index].f = f;
++index;
printf("%d | %s | %d | %f\n", i1, s, i2, f);
}
fclose(file);
qsort(array, n_records, sizeof(*array), compare_record);
for (int i = 0; i < n_records; ++i)
printf("%d | %s | %d | %f\n", array[i].i1, array[i].s, array[i].i2, array[i].f);
// Don't forget to free the memory allocated by strdup().
}
It seems that you just created a structure pointer but you don't give it a variable name.
Try this:
struct p_structure *your_var_name =malloc(n_records*sizeof(struct record_type*));
If it won't work, could you provide the code of your structures please ?
#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.
int f(){
struct NUMBER {
int A;
int B;
};
struct NUMBER *num = malloc(sizeof(struct NUMBER));
num->A = 1;
num->B = 2;
int x = num->B;
return x;
}
int main(){
int z = f();
printf("%d\n", z);
}
Obviously, ./a.out will show 2.
My question: Can I access struct member by an argument of function? i.e. f(A) return 1, and f(B) return 2. Thanks a lot.
Not at all elegant, but I think it shows you what you need to do/know.
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
struct NUMBER {
int A;
int B;
};
struct NUMBER extNumber = {1, 2};
int f(int offset) {
int iRet = -1;
if (offset == offsetof(struct NUMBER, A)) {
iRet = extNumber.A;
} else if (offset == offsetof(struct NUMBER, B)) {
iRet = extNumber.B;
}
return iRet;
}
int main (int argc, char **argv) {
struct NUMBER number;
int iVal;
iVal = f(offsetof(struct NUMBER, A));
printf ("A : %d\n", iVal);
iVal = f(offsetof(struct NUMBER, B));
printf ("B : %d\n", iVal);
}
Can I access struct member by an argument of function?
I think you are also assuming struct is not visible outside the function. Now if the person who wrote main does not have visibility into the function (say it is part of a library), then the answer is NO.
Otherwise if author of main can see internals of the function, then: Can someone come up with a fancy way to access struct member inside the function via function argument? Towards that lets think what does f(A) mean? Here, A is a name of struct member, so do you mean passing char A to f and translating that to struct member inside f [e.g. result = *(int *)num+(inchar-'A') where inchar is aninput parameter to the function of type char]. Similarly, one can imagine other ways.
As far as I understand your problem, the cleanest and most "C-like" solution is to pass a pointer to your struct to f(), where you populate it:
typedef struct _NUMBER
{
int A;
int B;
}
NUMBER;
void f (NUMBER* pvNumber)
{
pvNumber->A = 1;
pvNumber->B = 2;
return;
}
Call it like this:
int main ()
{
NUMBER vNumber;
int z;
f (&vNumber);
z = vNumber.A; // or vNumber.B
return 0;
}
So you don't select the desired member inside f(), but outside of it.
Yes. you need to define some way to access to member desired, this is usually done with constants, or an enum. As an aside, you should always check the pointer returned by malloc() before using it.
#define GET_A (0)
#define GET_B (1)
int f(int selector){
struct NUMBER {
int A;
int B;
};
int result;
struct NUMBER *num = malloc(sizeof(struct NUMBER));
if (!num)
return -1; // or some other error code...
num -> A = 1;
num -> B = 2;
switch(selector)
{
case GET_A: result = num->A; break;
case GET_B: result = num->B; break;
// etc... if you have more members in your struct.
default: result = -1; break; // some error code.
}
free(num)
return result;
}
int main(){
int z = f(GET_B);
printf( "%d\n" , f(GET_B));
}
I try to write a function, that finds void pointers in a data structure. The function has to cast the void* to any kind of struct.
Let's say I write a struct, which I store in my data sturcture in form of a void pointer. Then I calls the function, which prints information of all stored data elements.
To do that the function has to know to which type it should cast.
So my question is: Is it possible to give the function the informations it needs in form of a parameter somehow?
example code:
typedef struct{
int a, b
} teststruct;
void DSOut(datastructure* ds, datatypeinfo dt){
//...
//search for data in ds
//...
//if data is found cast it to the type defined in dt
//and print out the a and b fields
}
int main(){
datastructure* ds = DSCreate(4, 3); //can hold any type of data,
//but should hold just one at a time
//4 and 3 are just example parameters
teststruct ts;
ts.a = 4;
ts.b = 10;
teststruct ts2;
ts2.a = 6;
ts2.b = 12;
//Add the teststructs to the data-structure
DSAdd(2, 2, ts); //the numbers are just for example
DSAdd(4, 1, ts2);
datatypeinfo dt = teststruct; //stores the type teststruct for DSOut
DSOut(ds, dt); //function, that prints information of all added teststructs
return 0;
}
in this example DSOut(x,y) should print the following:
- on position 2, 2 is an element which holds following data: 4, 10.
- on position 4, 1 is an element which holds following data: 6, 12.
Do you think this is possible ?
Types cannot be passed as parameters in C, so the short answer to your question is "no, it cannot be done", at least not in the general case. You could pass something that would allow you to identify one of a limited set of types, and then hard-code how to handle each of those types (I'm thinking of a big switch statement). Since you don't specify what datatypeinfo looks like, it isn't clear how general you expect it to be.
I can think of adding a type identifier field to your struct and check it's value to decide how to print it, and initialize the structs with functions to take care of the type field
enum Types {
Point3D,
Point2D
};
struct Base {
enum Types type;
};
struct Point3D {
enum Types type;
int x;
int y;
int z;
};
struct Point2D {
enum Types type;
int u;
int v;
};
void print(void *data)
{
switch (((struct Base *)data)->type)
{
case Point2D:
{
struct Point2D *point;
point = (struct Point2D *)data;
printf("2D: %d, %d\n", point->u, point->v);
}
break;
case Point3D:
{
struct Point3D *point;
point = (struct Point3D *)data;
printf("3D: %d, %d, %d\n", point->x, point->y, point->z);
}
break;
}
}
void initialized2dPoint(struct Point2D *const point, int u, int v)
{
if (point == NULL)
return;
point->type = Point2D;
point->u = u;
point->v = v;
}
void initialized3dPoint(struct Point3D *const point, int x, int y, int z)
{
if (point == NULL)
return;
point->type = Point3D;
point->x = x;
point->y = y;
point->z = z;
}
int main(void)
{
struct Point2D point2d;
struct Point3D point3d;
initialized2dPoint(&point2d, 1, 2);
initialized3dPoint(&point3d, 3, 4, 5);
print(&point2d);
print(&point3d);
return 0;
}
I'm currently doing practice exams for a test I will have next monday and I came across something that confused me!
I have the following structs:
struct shape2d {
float x;
float y;
};
struct shape3d {
struct shape2d base;
float z;
};
struct shape {
int dimensions;
char *name;
union {
struct shape2d s1;
struct shape3d s2;
} description;
};
typedef struct shape Shape;
I have to make a function that 'creates' a shape with the following signature:
Shape *createShape3D(float x, float y, float z, char *name);
Because I'm dealing with an union of structs, I'm not quite sure how to initialize all the fields I need!
Here's what I have so far:
Shape *createShape3D(float x, float y, float z, char *name) {
Shape *s = (Shape *) malloc(sizeof(Shape));
s->dimensions = 3;
s->name = "Name...";
// How can I initialize s2?
return s;
}
Any help would be apprectiated!
First you need to strcpy name to s->name.
strcpy(s->name, "Name ...");
You can initialize s2 as
s->description.s2.z = 0;
s->description.s2.base.x = 0;
s->description.s2.base.y = 0;
You can read up more on unions in a book. You can also look here
http://c-faq.com/struct/union.html
http://c-faq.com/struct/initunion.html
http://c-faq.com/struct/taggedunion.html
You can do it like this:
s->description.s2.base.x=1;
s->description.s2.base.y=2;
s->description.s2.z=3;
As you can see, the syntax gets a little heavy at times, so it may make sense to define functions for accessing individual coordinates off a pointer to the structure:
float getX(Shape *s) {
if (dimensions == 2) {
return s->structure.s1.x;
} else {
return s->structure.s2.base.x;
}
}
void setX(Shape *s, float x) {
if (dimensions == 2) {
s->structure.s1.x = x;
} else {
s->structure.s2.base.x = x;
}
}
// Define similar functions for Y and Z
Now your initialization routine would change to more readable
setX(s, 1);
setY(s, 2);
setZ(s, 3);
Shape *createShape3D(float x, float y, float z, char *name) {
Shape *s = (Shape *) malloc(sizeof(Shape));
s->dimensions = 3;
s->name = malloc (strlen(name) + 1);
strcpy(s->name, name); // Copy the value of name
s->description.s2.base.x = x;
s->description.s2.base.y = y;
s->description.s2.z = z;
return s;
}
Also make sure to free up the memory for s->name before freeing up Shape* s