2

How would I pass a structure from one function to another?

typedef char word_t[MAX_WORD_LEN+1];

typedef struct {
    int nwrds;
    word_t words[MAX_PARA_LEN];
} para_t;

int
main() {
    para_t onepara;
    while (get_paragraph(onepara, MAX_PARA_LEN) != EOF) {
        put_paragraph(onepara, MAX_SNIPPET_LEN);
    }
    end_output();
    return 0;
}

int
get_paragraph(para_t p, int limit) {
    int d, i;
    word_t w;
    for (i=0;i<limit;i++) {
        if ((d=get_word(w, MAX_WORD_LEN))==EOF) {
            return EOF;
        } else if(d==WORD_FND) {
            strcpy(p.words[i], w);
        } else if (d==PARA_END) {
            new_paragraph();
            break;
        }
    }
    return PARA_FND;
}

void
put_paragraph(para_t p, int limit)  {
    int i;
    for (i=0;i<limit; i++)  {
    printf("%s\n", p.words[i]);
    }
}

I've used strcpy to copy the word 'w' to the array in structure 'p' (in get_paragraph) but when I go to print out that structure, I have trouble getting any output. Currently the put_paragraph outputs no string but I can't figure out why.

The get_word function in get_paragraph works correctly to identify a word and I haven't included it to save space.

3 Answers 3

2

You need to pass a pointer to a para_t if you want the function to modify it in a way that is visible to the caller.

Everything in C is passed by value, so a copy of your structure is passed to the get_paragraph function, and only a copy is modified. You need to pass a pointer if you wish the argument to be modified by the function.

typedef struct {
    char p[10];
} foo;

void bar(foo *f) {
    strcpy(f->p, "hello");
}

int main() {
    foo f = {0};
    bar(&f);
    printf("%s", f.p);  // prints "hello"
}

Since everything is pass by value, if words were a pointer instead of an array, this would have worked (though I would still pass a pointer, no need to make a copy here).

The pointer would have been copied, but a pointer's value is a memory address, so that would have been maintained in the copy, and the same chunk of memory that the original words variable referred to would have been modified.

typedef struct {
    char *p;
} foo;

void bar(foo f) {
    strcpy(f.p, "hello");
}

int main() {
    foo f = {0};
    f.p = malloc(10);
    bar(f);
    printf("%s", f.p);  // prints "hello"
}

On a side note...

It follows then that, if the function needs to assign a completely new value to the argument itself, you must use yet another level of indirection, i.e., a pointer to a pointer.

Sign up to request clarification or add additional context in comments.

Comments

1
while (get_paragraph(onepara, MAX_PARA_LEN) != EOF) {
        put_paragraph(onepara, MAX_SNIPPET_LEN);
    }

In your code, you have passed the structure variable onepara by value, and when you pass a variable by value, only a copy of the variable will be accessed by the function and not the actual value - therefore any modification you make to the variable will be made to the copy and will not be reflected in the variable in the calling function.

In your case, you have passed onepara by value, but for your code to work as intended, you need to pass the address of onepara while calling get_paragraph and put_paragraph.

The function declarations should look something like,

int get_paragraph(para_t *p, int limit)

void put_paragraph(para_t *p, int limit)

And while calling the above functions, you need to pass the address of one_para

while (get_paragraph(&onepara, MAX_PARA_LEN) != EOF) {
        put_paragraph(&onepara, MAX_SNIPPET_LEN);

Inside the functions get_paragraph and put_paragraph, you need to access the members of the strucure by the -> operator instead of the . operator as follows:

p->words[i] (instead of p.words[i])

For example, you would do strcpy as,

strcpy(p->words[i], w)

Comments

0

You can just pass it (and return as well):

#include <stdio.h>

typedef struct
{
  int x;
  const char* str;
} T;

T fxn(T t)
{
  t.x++;
  t.str++;
  return t;
}

int main(void)
{
  T t1 = { 1, "XYZ" };
  T t2;
  printf("t1: %d, %s\n", t1.x, t1.str);
  t2 = fxn(t1);
  printf("t1: %d, %s\n", t1.x, t1.str);
  printf("t2: %d, %s\n", t2.x, t2.str);
  return 0;
}

Output (ideone):

t1: 1, XYZ
t1: 1, XYZ
t2: 2, YZ

The above example shows how to pass (and return) structures by value. fxn(), as you can see, gets a copy of what's being passed to it. So, if you want to modify the structure being passed, you have to either return the new structure as in the above example or pass the structure by reference:

#include <stdio.h>

typedef struct
{
  int x;
  const char* str;
} T;

void fxn2(T* t)
{
  t->x++;
  t->str++;
}

int main(void)
{
  T t1 = { 1, "XYZ" };
  printf("t1: %d, %s\n", t1.x, t1.str);
  fxn2(&t1);
  printf("t1: %d, %s\n", t1.x, t1.str);
  return 0;
}

Output (ideone):

t1: 1, XYZ
t1: 2, YZ

6 Comments

-1 You changed the problem. If the member of the struct were indeed a pointer then yes, you could pass a copy of the structure itself because a copy of the pointer would be passed, and the copied pointer would refer to the same address as the original. However, as words is an array, you cannot; you must pass a pointer to the structure if the function needs to modify said array.
@EdS. Not true. You can pass any kind of structure, with array members as well: ideone.com/exSPn. Btw, I have included an example of passing a structure by reference in my answer.
You are simply returning the modified copy of the original argument. Your own example shows that I am in fact correct; the argument is not modified, only a copy is. The OP is performing a strcpy on the argument to get_paragraph and expecting it to be modified. I'm not saying your original example is wrong, I'm just saying it doesn't address the problem that the OP is having
That said, I'll remove the downvote per your recent edit... though nothing in C is passed "by reference* as you say. Everything is passed by value, as the pointer in your second (pass "by reference" example) is being passed by value. Functions always get a copy, always. You simply add levels of indirection.
@EdS. That's a common idiom/lingo, which can be somewhat misleading in C. Thanks.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.