2

I would like learn how to pass, by reference, an array of structs to the second function called/executed from within the first function. My goal is to modify/change the contents of arbitrary struct from the second function only. The code below works, but, unfortunately, does not do exactly what I want to achieve. I would to have access to arbitrary struct within second function. In other words, I would like to process all structs (using for loop) within second function by calling/executing first function in main only once and not using for loop.

The second function, in the code below, is named passByReference_inner.

array_of_struct.h :

struct card
{
    int face;
    int nose;
};

typedef struct card HEAD ;

/* prototype */
extern void passByReference(HEAD **c);      /* first function */
extern void passByReference_inner(HEAD *c); /* second function */

first function: (passByReference)

#include <stdio.h>
#include "array_of_struct.h"

void passByReference(HEAD **c)
{
    passByReference_inner (*c);   /* second function */
}

second function: (passByReference_inner)

#include <stdio.h>
#include "array_of_struct.h"

void passByReference_inner(HEAD *c)
{
    c->face = (c->face) + 1000;
    c->nose = (c->nose) + 2000;
}

main:

#include <stdio.h>
#include "array_of_struct.h"

int main(void)
{
    int             i;
    static HEAD     c[12];
    static HEAD *cptr[12];

    for ( i = 0; i < 12; i++ )
    {
        c[i].face = i + 30;
        c[i].nose = i + 60; 
        cptr[i]   = &c[i];
    }

    for ( i = 0; i < 12; i++ )
    {
        passByReference(&cptr[i]);  /* first function */
    }
    return 0;
}
6
  • I wish all questions were like this one... Commented Dec 28, 2014 at 4:45
  • the C language cannot pass by reference, only by value; however, it can pass a pointer. Commented Dec 28, 2014 at 5:01
  • in main(), the variable 'cptr' and all usage can be completely replaced with references to '&c[i]' Commented Dec 28, 2014 at 5:04
  • in main() this line: 'cptr[i] = &c[i]' does nothing and can be eliminated Commented Dec 28, 2014 at 5:05
  • in the code, the number '12' is a 'magic' number that occurs several places in the code. that number should be defined by #define MAX_COUNT (12) then MAX_COUNT used in all places where '12' is currently being used. Commented Dec 28, 2014 at 5:07

4 Answers 4

4

I think what you are trying to do is this

#include <stdio.h>

struct card
{
    int face;
    int nose;
};

typedef struct card HEAD ;

/* prototype */
void passByReference(HEAD *c, int count);      /* first function */
void passByReference_inner(HEAD *c); /* second function */

void passByReference(HEAD *c, int count)
{
    int i;
    for (i = 0 ; i < count ; i++)
        passByReference_inner (&(c[i]));   /* second function */
}

void passByReference_inner(HEAD *c)
{
    c->face = (c->face) + 1000;
    c->nose = (c->nose) + 2000;
}

int main(void)
{
    int  i;
    HEAD c[12]; /* you don't need static here (do you know what static is for?) */

    for ( i = 0; i < 12; i++ )
    {
        c[i].face = i + 30;
        c[i].nose = i + 60;
    }
    /* 
     * the element count of the array is sizeof(c) / sizeof(c[0]) 
     *    (totalSizeOfArray) / (indivudualElementSizeOfArray).
     */
    passByReference(c, sizeof(c) / sizeof(c[0]));  /* first function */

    return 0;
}

what you should know is that arrays in c decay to a pointer that points to their first element when passed as parameters to functions.

Since you want to process all the structs in the second function, I don't see the need for the first function, anyway this is how you would do it then

#include <stdio.h>

struct card
{
    int face;
    int nose;
};

typedef struct card HEAD ;

/* prototype */
void passByReference(HEAD *const c, int count);      /* first function */
void passByReference_inner(HEAD *const c, int count); /* second function */

void passByReference(HEAD *const c, int count)
{
    passByReference_inner(c, count);   /* second function */
}

/* HEAD *const c prevents the pointer c to be changed
 * this way it will never point anywhere else.
 *
 * And you can be sure to alter the original data.
 */
void passByReference_inner(HEAD *const c, int count)
{
    for (int i = 0 ; i < count ; ++i)
    {
        c[i].face = (c[i].face) + 1000;
        c[i].nose = (c[i].nose) + 2000;
    }
}

int main(void)
{
    int  i;
    HEAD c[12]; /* you don't need static here (do you know what static is for?) */

    for ( i = 0; i < 12; i++ )
    {
        c[i].face = i + 30;
        c[i].nose = i + 60;
    }
    /* 
     * the element count of the array is sizeof(c) / sizeof(c[0]) 
     *    (totalSizeOfArray) / (indivudualElementSizeOfArray).
     */
    passByReference(c, sizeof(c) / sizeof(c[0]));  /* first function */

    return 0;
}

since you are effectively passing a pointer, you alter it's contents directly in both functions the first and the second.

One more thing, you don't really need the static keyword, specially in main(), static keeps the value of the variable between function calls, and since main() will normally be called only once in the lifetime of the program... it doesn't make much sense to use static there.

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

12 Comments

Why would you make HEAD static if you a passing by reference?
I think OP wants the for loop inside of passByReference_inner. Doesn't really change the essence of the answer, but needs a little rearranging.
@DavidC.Rankin Are you confusing static with const?
@user3386109 you are right, I just re-read the question, some times I have trouble to understand english.
No problem, the wording in the question made it hard to keep track of all the functions, but your answer is good +1.
|
1

Your second function is correct.

A pointer to the first element of an array is effectively the same thing as the pointer to an array itself.

What you should do is

void passByReference_inner(HEAD *c, size_t n)
{
}

So, you'll pass the pointer to the first element of the array, and the number of elements in the array, something like this:

passByReference(c, sizeof(c)/sizeof(c[0]));

This will pass the pointer to the first element of the c array, and the number of elements in the array, to passByReference_inner(). sizeof(c) is the size of the entire array in bytes. sizeof(c[0]) is the size of an element in the array. So, if, for example, each struct is 10 bytes long (just an example), and you have an array of 12 structs, the size of the entire array is 120 bytes, and this calculates the value 120/10=12, the number of elements in the array, automatically.

When you use the name of an array object, in C/C++ that automatically becomes a pointer to the first element of the array.

In your function, you can work with the array in the following manner:

void passByReference_inner(HEAD *c, size_t n)
{
    for (size_t i=0; i<n; i++)
    {
        HEAD *p=c+i;

        // p is now a pointer to the ith element of the array
    }
}

Adding an integer n to a pointer advances the pointer to the next nth element of an array. Adding an integer value to a pointer doesn't advance the pointer by this number of bytes, but by the number of bytes in the object the pointer points to, multiplied by the number you're adding (or subtracting, same thing). That makes pointer arithmetic do the right thing.

6 Comments

"When you use the name of an array object, in C/C++ that automatically becomes a pointer " In C++, only in a context where a pointer is expected. You can pass pointers or references to arrays of a given size. (In C, a pointer to an array does seem to bind to any old pointer. I'm not sure if that is standard or a compiler extension.)
@juanchopanza there is no C++ in this question. And what is "does seem to bind to any old pointer" supposed to mean?
@iharob I was referring to a sentence in this answer, which mentions "C/C++" (which might suggest it applies to both languages since there is no hybrid C/C++ language). As for "... any old pointer", my phrasing is poor, but it seems in C you can say int (*p)[2] = &a; where a is an int. In C++ a would have to be an int[2].
@juanchopanza No you can't, in C a would have to be int[2] too. You can compile that for sure, but at least gcc would issue a warning. And regarding the C/C++ thing, yes no I see that in the answer, sorry.
@iharob I am not sure of the details, but at least clang issues an error in C++, and only a warning in C (my recollection is that recent versions of gcc behave in the same way.) My understanding is that an implementation has to issue an error in C++. In any case, my point about the sentence in question holds.
|
0
  • The following code compiles cleanly.
  • The following code moves the increment values loop
    to inside the passByReference() function.

/* 
 * Note: guard code is used in a header file
 *       so the header file can only be included once
 *       in each compilation unit 
 */

// note the inclusion of a 'guard' wrapper
// begin: array_of_struct.h file
#ifndef ARRAY_OF_STRUCT_H
#define ARRAY_OF_STRUCT_H

struct card
{
    int face;
    int nose;
};

// dont obsecure the code with useless typedef statements
//typedef struct card HEAD ;

#define MAX_CARDS (12)

/* prototype */
extern void passByReference(struct card *pCards);      /* first function */
extern void passByReference_inner(struct card *pCard); /* second function */
#endif
// end: array_of_struct.h


//first function: (passByReference), in different file

#include <stdio.h>
#include "array_of_struct.h" 

void passByReference(struct card *pCards)
{
    int i=0; // loop index

    for(i=0;i<MAX_CARDS;i++)
    {
        passByReference_inner (&pCards[i]);   /* second function */
    } // end for
} // end function: passByReference

// second function: (passByReference_inner), in different file

#include <stdio.h>
#include "array_of_struct.h"

void passByReference_inner(struct card *pCard)
{
    pCard->face = (pCard->face) + 1000;
    pCard->nose = (pCard->nose) + 2000;
} // end function: passByReference_inner

//main, in a different file

#include <stdio.h>
#include "array_of_struct.h"

int main()
{
    int i = 0; // loop index
    static struct card     cards[MAX_CARDS];

    for ( i = 0; i < MAX_CARDS; i++ )
    {
        cards[i].face = i + 30;
        cards[i].nose = i + 60;
    } // end for

    passByReference(&cards[0]);  /* first function gets ptr to whole array*/
    // could also be written as:
    // passByReference(cards);

    return 0;
} // end function: main

Comments

0

I've analyzed all three solutions (iharob, user3629249, Sam Varshavchik) and came to the conclusion that Sam Varshavchik and the second solution from iharob were right on the money. The first iharob's solution and user3629249 solution are, in essence, equal. They moved for loop from main to the first function. The second solution of the iharob's post matches the requirements from the initial post. Sam's solution gave me enough hints/instructions for 'how to move for loop from the main to the second function (which was, basically, what I did not know how to do it and therefore asked for help).

So, to make long story short, here is the source code which implements almost all suggestions from all contributors. The code compiles cleanly, so, beginners like me, can take it as-is and learn few details about pointer to pointer, pointer arithmetic and about array of structs.

array_of_struct.h (header file)

#ifndef ARRAY_OF_STRUCT_H
#define ARRAY_OF_STRUCT_H

/* HEAD structure definition */
typedef struct
{
    int face;
    int nose;
} HEAD;       // end structure HEAD

#define MAX_HEADS (12)

/* prototype */
extern void passByReference(HEAD **c, size_t n);
extern void passByReference_inner(HEAD *c, size_t n);

#endif

passByReference.c (first function)

#include <stdio.h>
#include "array_of_struct.h"

void passByReference(HEAD **c, size_t n)
{
    passByReference_inner (*c, n);
}

passByReference_inner.c (second function)

#include <stdio.h>
#include "array_of_struct.h"

void passByReference_inner(HEAD *c, size_t n)
{
    int   i;
    HEAD *p;

    printf("\nPOINTER ARITHMETIC: The value of struct's  members after PASS BY REFERENCE \n");
    for ( i = 0; i < n; i++ )
    {
        p = c + i;

        p->face = (p->face) + 1000;
        p->nose = (p->nose) + 2000;
        printf("struct[%i].face = %d  \n",i, p[0].face);
        printf("struct[%i].nose = %d  \n",i, p[0].nose);
    }

    printf("\nARRAY INDEX MATH: The value of struct's  members after PASS BY REFERENCE\n");
    printf("[NOTE: structs were updated in the for loop above]\n");
    for ( i = 0; i < n; i++ )
    {
        printf("struct[%i].face = %d  \n",i, c[i].face);
        printf("struct[%i].nose = %d  \n",i, c[i].nose);
    }
}

main.c

#include <stdio.h>
#include "array_of_struct.h"

int main(void)
{
    int     i;
    HEAD    c[MAX_HEADS];
    HEAD   *cptr;
    size_t  n;

    n = (sizeof(c) / sizeof(c[0]);

    printf("\nINITIALIZATION of all struct's  members\n");
    for ( i = 0; i < n; i++ )
    {
        c[i].face = i + 30;
        c[i].nose = i + 60; 
        printf("struct[%i].face = %d\n",i, c[i].face);
        printf("struct[%i].nose = %d\n",i, c[i].nose);
    }

    cptr = &c[0];
    passByReference(&cptr, n); 

    return 0;
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.