A Circular Reference

Adventures of a vagabond electron.

C Tips and Tricks[0]

| Comments

These posts document some of the C concepts that I often forget or confound and some idioms that I’ve encountered. It is intended as a quick reference (for myself). Most of it is not original work, some relevant sources can be found in the inline references, others might be burried in my subconscious.

Arrays

Whenever an array name appears in an expression except as the operand of unary & or the sizeof operator, the value of the array name becomes a pointer to the first element of the array.

1
2
3
4
5
6
int a[10];
int (*p_a)[10] = &a;	// &a is a pointer to an array of int with bounds 10, i.e. p_a = &a[0];
int *p_int = a;			// a is a pointer to int, i.e. p_int = &a[0]

int b[10][20];
int (*p_b)[20] = b;		// b is a pointer to an array of 20 ints, i.e. p_b = &b[0];

Arrays as function parameters

You can declare functions with array parameters, this is exactly equivalent to using the more common pointer syntax. The type qualifiers following the [ act as if they followed the * when the parameter’s type is rewritten as a pointer type. You can also use the static keyword within the [] to specify a minimum size for the caller passed array pointer. Thus:

1
2
3
int foo(int a[n]);  // is the same as foo(int* a)
int f(float array[const restrict]); // can be read as int f(float *const restrict array);
void foo(int a[static 10]); //  actual argument corresponding to a must be an array with at least 10 elements

Multidimensional arrays (Variable Length)

In C90 multidimensional arrays can be used with the convinent [i][j][k] indexing syntax only if the total size of N-1 dimensions (bounds a.k.a stride) are known at compile time. You don’t need to know the size of the last dimension as the stride of this dimension is equal to the sizeof(array_element_type). C99 created VLAs to overcome this restriction. Arrays whose size is determined at runtime are called Variable Length Arrays (VLA).

1
2
3
4
5
6
7
8
9
10
11
12
// C90 multidimensional arrays (using a single dimension array)
float a[m*n*sizeof(float)];
for (i = 0; i < m; ++i)
  for (j = 0; j < n; ++j)
	a[i*n + j] = 1.0;

// C99 multidimensional indexing
float a[m][n];
int i, j;
for (i = 0; i < m; ++i)
  for (j = 0; j < n; ++j)
	a[i][j] = 1.0;

References:

Randy Meyers has a series of informative articles in the now defunct C/C++ Users Journal that discuss VLAs and other topics summarized on this page in more detail. The journal arcives are available here. Dr.Dobb’s journal (also defunct) has copies of the articles too. VLA Part 1 VLA Part 2 VLA Part 3 VLA Part 4

C99 C99 Rationale C11 Final Draft

Strings

String literals v/s arrays

A string in C is simply an array of chars terminated by a '\0'. Initialized strings can be created in two ways - one is to statially allocate them in memory and hold a pointer to address where the string is stored, and the other is to store the string as an array of chars. In the first case they are constant and it’s undefined behavior to modify them, while in the second case their contents can be modified [C99 N1256 draft 6.7.8/32 “Initialization”].

1
2
3
/* pChar is a pointer to the actual lccation of the string, so we require an additional 4 bytes or more to store the pointer compared to string[] */
char* pChar = "I'm a string literal, I can be modified but no guarantees on the result"; // This always goes into the data segment
char string[] = "I'm a string array, can I be modified?"; // This could go into the stack or data segment depending on where it's defined

Anonymous string literals can also be used as in printf("Another literal"), in this case the pointer to the literal is implicitly passed to printf() on the stack. This by default allocation of debugging strings into data memory eat up a lot of useful RAM. Some targets have a way to relocate strings into program memory, for example AVR has the PROGMEM keyword which the Arduino platform extended to the F(x) macro.

Another trick is to use the C99 compound literal sytax to convert the string literal into a char array and push it onto the stack. However this trick only works for short length string literals, larger literals are stored in the data segment and then coped onto the stack at runtime by your smart ass compiler. The boundary was 18 bytes on an embedded MCU I tested with.

1
2
3
4
5
6
7
8
9
// AVR specific redirection into flash
#define PSTR(s) ((const PROGMEM char *)(s))

// Convert a string literal into an unnamed char array
printf("%s", (char []){"This is a string array stored on the stack"});
// A macro to do this
#define F(x)	(char []){x}
// A string with extended ascii chars
char ex = "An ex char to end it \xB0";

Jagged char arrays

C does not natively support jagged arrays but you can declare an array of variable length strings like:

1
2
char* pChar2D[] = {"A long long long string", "short", "something else"};
printf(pChar2D[0]); // A long long long string

How does it work? Relook at the declreation of pChar2D- it is an array of pointers to char, which means that when you say pChar2D[0] you end up getting the address of the string literal "A long long long string". Not surprisingly, this is exactly how jagged arrays of other types are programatically dealt with usually. i.e.

1
2
3
4
int r0[] = malloc(sizeof(int) * 10);
int r1[] = malloc(sizeof(int) * 2);;
int *jagged[] = { r0, r1 };
printf("%d %d, jagged[0][9], jagged[1][1]);

If you are unsure about a C declerations, they can be looked up at cdecl.org

Designated Initializers

Initializing individual elements with arrays and structs can be done with designated initializers. Elements that are not specifically initialized are automatically initialized to 0. This is clearly better than the old method of having to initialize members individually which lends garbage values to uninitialized elements. More details here

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Initializing an array
int a[100] = {[0]=5, [99]=100};

// Struct
struct S1 {
  int i;
  float f;
  int a[2];
};

struct S1 x = {
  .f=3.1,
  .i=2,
  .a[1]=9
};

Compound literals

Just like how like languages like C# allow you to create and manipulate anonymous objects, C99 allows you to do the same thing with C types like int, struct, union, array etc. These are called compound literals. You are allowed to take the address of these constants and pass them around as function parameters. The basic syntax is (<type>){<initializer-list-expression>}.

1
2
3
4
(float){3.14};
(struct POINT){10, 10};
(char []){"Compound Literal Array"};
(const char[]){"A CONSTANT compound literal array"};

Comments