Suppose we have:
typedef struct {
uint8_t someVal;
} Entry
typedef struct {
Entry grid[3][3];
} Matrix
//Make a 3x3 matrix of all 0s
Matrix emptyMatrix(void) {
Entry zero = {.value = 0}
Matrix matrix;
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++) {
//Shallow copy empty struct
matrix.grid[i][j] = zero;
}
return matrix;
}
Matrix myMatrix = emptyMatrix();
I understand that in C we're allowed to return a struct from a function so this works and I've tested it. However, it's unclear to me HOW the assignment works.
Does the compiler allocate the memory for myMatrix
then copy each Entry
element of the array in the Matrix
struct returned by emptyMatrix()
?
I guess it would also be helpful to know the memory map of Matrix
- I assumed that since grid
is an array that Matrix
's memory would contain pointers. However, it apparently stores the value . If this is the case, my guess for how the assignment works makes much more sense to me.
Edit: It seems like people are answering the question incompletely. I want to know whether my guess of how the assignment works is correct.
Each instance of Matrix
will contain a 3x3 array of Entry
. When you assign one instance of Matrix
to another, the contents of the source matrix will be copied to the destination matrix.
Arrays are not pointers. Array expressions will "decay" to pointers if the expression is not the operand of the sizeof
or unary &
operators, or is not a string literal used to initialize a character array in a declaration.
For example, if you had a function call like
printMatrix( myMatrix.grid );
the expression myMatrix.grid
has type "3-element array of 3-element array of Entry
"; since it's not the operand of the sizeof
or unary &
operator, it "decays" to an expression of type "pointer to 3-element array of Entry
" ( Entry (*)[3]
) and the value of the expression is the address of the first element of grid
(which will also be the address of the whole Matrix
instance).
The ABI for each environment defines how structures are passed and returned by value. A common choice is this:
small structures, up to the size of 2 or 4 registers are returned in registers.
for larger objects, the caller allocates space on its stack frame for the return value and passes a pointer to the function. When returning, the function copies whatever object is being returned into the space to which it received a pointer for the return value. That's it. This simple method allows for recursive calls.
the optimizer tries to minimize the amount of copying, especially if it can expand the function inline or if the returned value is stored into an object, as opposed to discarded or passed by value to another function.
It does not matter if the structure has one or more member arrays. The same method applies to unions as well.
Identifiers bound to arrays may be interpreted as pointers, but that doesn't mean that the array variables are pointers.
The storage for the array is part of the memory layout of the struct itself. The same way as arrays declared on the stack are on the stack itself.
You can test this by yourself by checking sizeof(Matrix)
.
So in short:
Does the compiler allocate the memory for myMatrix then copy each Entry element of the array in the Matrix struct returned by emptyMatrix()?
Yes
Matrix
is a data type struct struct {Entry grid[3][3];}
. For every object of the type Metrix
memory of size Entry grid[3][3]
will be allocated.
Function emptyMatrix
is returning an object of type Matrix
and the object will be returned by value just like any other object.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.