-4

I am currently learning C. However I am stuck on returning structs, returning 2 different char arrays. This is my code

struct wordsReturn
{
    char wordspass[1000];
    char words2[1000];
};

static wordsReturn wordsfunction(char *wordspass) 
{
    char words[] = wordspass;
    char words2[] = "words also in here";

    return words, words2 ;
}

void main()
{
    char *words = "words in here";

    wordsReturn twowords = wordsfunction(&words);
}

Making adjustments here and there results in many different errors in my compiler. I am getting wordsReturn is undefined errors and incorrect return types errors when im trying to return. I am following a guide but its in c++ but im in C which I think could be the problem. I have tried using pointers but that didnt help me I was still getting many errors. I have tried many solutions on the internet but I could not find one which helped me return 2 different char arrays. My goal is return 2 different char arrays. Thanks for any help.

J. Doe
  • 171
  • 4
  • 11

4 Answers4

2

You can (generally) use compound literals to create and populate a struct in a single line, allowing you to write something like:

// note that this is a different definition from your struct
struct something
{
    char * a;
    char * b;
};

static struct something create(char * x, char * y) 
{
    return (struct something){ x, y };
}

Or, if you want to be explicit about the order of parameters, you can use designated initializers:

static struct something create(char * x, char * y) 
{
    return (struct something){ .a = x, .b = y };
}

However, in your particular case:

  1. You cannot assign a char pointer to a member of your struct, because your struct does not contain pointers, it contains arrays of chars (meaning that the struct contains the actual space needed to store the data). In this case, you will have to copy the data into the struct before returning it.

  2. You shouldn't return a struct of this size (2000 bytes) from the function, because all objects in C are returned by value, meaning that the entire struct instance has to be copied each time you pass it around (or return it from a function).

So arguably the only reasonably approach would be to pass a pointer to your struct into the function, and then populate the object with a longer lifetime:

struct wordsReturn
{
    char wordspass[1000];
    char words2[1000];
};

static void wordsfunction(struct wordsReturn * result, const char * wordspass)
{
    strncpy(result->wordspass, wordspass, sizeof result->wordspass);
    result->wordspass[sizeof result->wordspass - 1] = 0;

    // or something like that, check this thread for a safe strcpy alternative
    // https://stackoverflow.com/a/41885173/69809
}

And then you would pass a pointer to an already allocated struct:

struct wordsReturn words;

void somewhere(void)
{
     wordsfunction(&words, "example");
}
vgru
  • 49,838
  • 16
  • 120
  • 201
1

You cannot return multiple variables using a return statement.

What you need to do is

  • Inside the called function, create a local variable of that structure type, and populate the values accordingly.
  • return the variable.
  • Collect it into another variable of that structure type in the caller.
  • Access the structure member variables to get the values.
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
0

Please try the following code.

#include <stdlib.h>
#include<string.h>

struct wordsReturn
{
    char wordspass[1000];
    char words2[1000];
};

struct wordsReturn wordsfunction(char *wordspass)
{
    struct wordsReturn ws;
    strcpy(ws.wordspass,wordspass);
    strcpy(ws.words2, "some random text");
    return ws;
}

int main()
{
    char *words = "words in here";

    struct wordsReturn twowords = wordsfunction(words, ws);
    printf("%s\n%s", twowords.wordspass, twowords.words2);
}
sattva_venu
  • 677
  • 8
  • 22
0

When you pass/return structures it is desirable to work with their addresses. Do not pass/return structures by value (i will explain why below).

I can not understand what you code should do, but let me give an example that will make you understand how passing structures can be made possible in C

Suppose we have the following structure:

struct tagPerson
{
    char FirstName[100];
    char LastName[100];
};
typedef struct tagPerson Person; // <-- without this line, Person is just a tag, not a valid datatype

Now, you want to make a function that will return a Person. This is how:

Person CreatePerson(const char* FirstName, const char* LastName)
{
    Person p; // <-- this will create a person.
    strcpy (p.FirstName, FirstName); // <-- this is how you copy a string in C
    strcpy (p.LastName, LastName);

    // and now just return the person.
    return p;
}

Inside your main you can call the CreatePerson function like this:

int main()
{
    Person p = CreatePerson("Alex", "Anderson"); // not great names tho :)
    return 0;
}

Now, the CreatePerson function is not quite good, because it returns a Person by value. If you check with the sizeof operator, you can see that sizeof(Person) is 200 bytes.

Usually, functions in C and C++ use data registers to return values and copy values for the function parameters.

The ideal case is when the parameters and the return value fit into a small amount of registers.

In our CreatePerson function however, the variable p needs to remain on the stack and (probably) the eax register will hold its address. The line from main : Person p = CreatePerson(...); will be broken down into allocating space on the stack for the new variable p and copy what lies where eax points.

The actual explination is much bigger and does not fit your question, so i'll skip it. If you want to learn more about it, google about C/C++ function parameters and registers.


Luckily, the solution is simple. Pass or return object addresses instead. Here is how the CreatePerson function can be modified to do the same thing, but a lot better in terms of stack memory.

void CreatePerson(Person* p, const char* FirstName, const char* LastName)
{
    // You no longer need to declare a person.
    // The address where data should be filled with the first and last name
    //  if provided through the parameter p.

    strcpy (p->FirstName, FirstName);
    strcpy (p->LastName, LastName);

    // you no longer need to return anything.
}

With the above declaration of the function, only space for 3 pointers is necessary (that actually means 12 bytes on x32 or 24 bytes on x64). You can call it from main like this using the unary operator & to pass the address of the variable p:

int main()
{
    // You still need to create a Person instance
    //  you just do it outside the function.
    Person p;

    CreatePerson(&p, "Alex", "Anderson"); // not great names again but...

    // now just print the name
    printf("The person is called %s %s.", p.FirstName, p.LastName);

    return 0;
}

Again, i do not know what you wanted to do with your code, but i see no good reason to return structures with the return keyword. Parameters can also be used in and out operations. There is however, one single case where the return comes in more handy, and that is when you need to dynamically allocate the structure. Suppose we needed person on the heap and not on the stack, this is how the CreatePerson function could have looked:

Person* CreatePerson(const char* FirstName, const char* LastName)
{
    // You now need to allocate person on the heap.
    Person* p = malloc(sizeof(Person));

    strcpy (p->FirstName, FirstName);
    strcpy (p->LastName, LastName);

    // Return the address where person is allocated
    return p;
}

And this is how you now use it in main:

int main()
{
    // You now need a pointer.
    Person* p = CreatePerson("Alex", "Anderson");

    // Do something with it...
    printf("The person is called %s %s.", p->FirstName, p->LastName);

    // Now that you are done, free the memory where the person is stored.
    free(p);

    return 0;
}

Because you are new to C, i'm going to also tell you this:

  • You need to include <stdlib.h> for malloc() and free().
  • You need to include <stdio.h> for printf()
  • You need to include <string.h> for strcpy()
Tudor
  • 436
  • 3
  • 10