...
C functions may not return arrays; however, functions can return a pointer to an array or a struct or union that contains arrays. Consequently, in any version of C, if a function call returns by value a struct or union containing an array, do not modify those arrays within the expression containing the function call. Do In C99 and older, do not access an array returned by a function after the next sequence point or after the evaluation of the containing full expression or full declarator ends.
Noncompliant Code Example
...
This noncompliant code example conforms to the C11 Standard; however, it fails to conform to C99. If compiled with a C99-conforming implementation, this code has undefined behavior because the sequence point preceding the call to printf() comes between the call and the access by printf() of the string in the returned object.
| Code Block | ||||
|---|---|---|---|---|
| ||||
#include <stdio.h>
struct X { char a[8]; };
struct X salutation(void) {
struct X result = { "Hello" };
return result;
}
struct X addressee(void) {
struct X result = { "world" };
return result;
}
int main(void) {
printf("%s, %s!\n", salutation().a, addressee().a);
return 0;
}
|
Compliant Solution (C11 and newer)
This compliant solution checks __STDC_VERSION__ to ensure that a pre-C11 compiler will fail to compile the code, rather than invoking undefined behavior.
| Code Block | ||||
|---|---|---|---|---|
| ||||
#include <stdio.h> #if __STDC_VERSION__ < 201112L #error This code requires a compiler supporting the C11 standard or newer #endif struct X { char a[8]; }; struct X salutation(void) { struct X result = { "Hello" }; return result; } struct X addressee(void) { struct X result = { "world" }; return result; } int main(void) { printf("%s, %s!\n", salutation().a, addressee().a); return 0; } |
Compliant Solution (C99 and older)
This compliant solution stores the structures returned by the call to addressee() before calling the printf() function. Consequently, this program conforms to both C99 and C11.
| Code Block | ||||
|---|---|---|---|---|
| ||||
#include <stdio.h>
struct X { char a[8]; };
struct X salutation(void) {
struct X result = { "Hello" };
return result;
}
struct X addressee(void) {
struct X result = { "world" };
return result;
}
int main(void) {
struct X my_salutation = salutation();
struct X my_addressee = addressee();
printf("%s, %s!\n", my_salutation.a, my_addressee.a);
return 0;
}
|
Noncompliant Code Example
This noncompliant code example attempts to retrieve an array and increment the array's first value. The array is part of a struct that is returned by a function call. Consequently, the array has temporary lifetime, and modifying the array is undefined behavior in both C99 and C11.
| Code Block | ||||
|---|---|---|---|---|
| ||||
#include <stdio.h>
struct X { int a[6]; };
struct X addressee(void) {
struct X result = { { 1, 2, 3, 4, 5, 6 } };
return result;
}
int main(void) {
printf("%x", ++(addressee().a[0]));
return 0;
}
|
Compliant Solution
This compliant solution stores the structure returned by the call to addressee() as my_x before calling the printf() function. When the array is modified, its lifetime is no longer temporary but matches the lifetime of the block in main().
| Code Block | ||||
|---|---|---|---|---|
| ||||
#include <stdio.h>
struct X { int a[6]; };
struct X addressee(void) {
struct X result = { { 1, 2, 3, 4, 5, 6 } };
return result;
}
int main(void) {
struct X my_x = addressee();
printf("%x", ++(my_x.a[0]));
return 0;
}
|
Exceptions
...
Risk Assessment
Attempting to modify an array or access it after its lifetime expires may result in erroneous program behavior.
...