Home

C notes

What happens when you have the same function name in two different files and one of them in not static ?

You might get a linking error saying that there are multiple definitions for that function. You can also see where the function was first defined in the compiler logs.

Compile C using visual studio compiler on windows

Open developer command prompt (which gets installed as a part of Visual Studio).

type> cl
type> cl main.c
type> main

MSVC: walkthrough-compile-a-c-program-on-the-command-line

A better way to write comparison statements

(NULL == ptr) instead of (ptr == NULL)

I remember one exam in which I had spent half an hour to spot this assignment instead of comparison error.

People might forget to put ! (or the extra = for equality, which is more difficult to spot) and do an assignment instead of a comparison.

Putting the NULL in front eliminates the possiblity for the bug, since NULL is not a l-value (i.e. it can’t be assigned to).

Few ways to implement a function like insertAtBeginningOfLinkedList()

Initialization of struct

If the data is a static or global variable, it is zero-filled by default, so just declare it myStruct _m;.

If the data is a local variable or a heap-allocated zone, clear it with memset as:

memset(&_m, 0, sizeof(myStruct));

Using memset for local structures is better, and it conveys better the fact that at runtime, something has to be done (while usually, global and static data can be understood as initialized at compile time, without any cost at runtime).

= {} ; empty braces for initialization is a GNU extension.

Note that in C99, a new way of initialization, called designated initialization can be used too:

myStruct _m1 = {.c2 = 0, .c1 = 1};

stackoverflow: initializing-a-struct-to-0

Caution using memset to initialize: You can’t memset an array correctly which is of the type other than 1 byte

#include <stdio.h>
#include <string.h>

typedef enum
{
    ON,
    OFF,
    NONE,
    _AAA,
    _AAB,
    _AAC,
} MYENUM;

static MYENUM MyList[2][4];

int main(void)
{
    for (int i = 0; i < 4; i++)
    {
        printf("\n%d\n", MyList[0][i]);
    }
    memset(MyList[0], NONE, sizeof(MyList[0][0]) * 4);
    for (int i = 0; i < 4; i++)
    {
        printf("\n%d\n", MyList[0][i]);
    }
    printf("\n%d\n", sizeof(MYENUM));
    printf("\n%d\n", NONE);
    return 0;
}

/*
OUTPUT -


0

0

0

0

33686018

33686018

33686018

33686018

4

2

*/

memset() will set each byte to NONE (2) instead of every 4 bytes.

MYENUM will be 4 bytes. So MyList[0][0] will be 0x02020202 instead of 0x00000002.

We should therefore, use a for loop if we want to set a non-zero value.

stackoverflow: memset-enum-array-values-not-setting-correctly-c

Usually, it gives correct result if setting zero value.


#include <stdio.h>
#include <string.h>

int main(void)
{
    size_t bbb[3] = {2, 4, 5};
    memset(bbb, 0, sizeof(size_t));

    printf("sizeof size_t %d\n", sizeof(size_t));
    printf("sizeof bbb %d\n", sizeof(bbb));
    printf("%d\n", bbb[0]);
    printf("%d\n", bbb[1]);
    printf("%d\n", bbb[2]);
    printf("\n**************\n");

    memset(bbb, 0, sizeof(bbb));
    printf("%d\n", bbb[0]);
    printf("%d\n", bbb[1]);
    printf("%d\n", bbb[2]);

    return 0;
}

/*
OUTPUT -

sizeof size_t 8
sizeof bbb 24
0
4
5

**************
0
0
0

*/

memset, memcpy and memcmp

memcpy() copies from one place to another. memset() just sets all pieces of memory to the same value.

Example:

memset(str, '*', 50);

The above line sets the first 50 characters of the string str to * (or whatever the second argument of the memset).

memcpy(str2, str1, 50);

The above line copies the first 50 characters of str1 to str2.

It’s worth pointing out that the mem*() functions do not know about string terminators. The second example above will do bad things if str1 is shorter than 50 characters. It’s only safe to use mem*() functions on string data when you have already validated the lengths involved.

memcmp() (compares two blocks of memory) is in <string.h> in C. Use man memcmp (on terminal) to read description and to find in which header file it is declared.

stackoverflow: what-is-the-difference-between-memset-and-memcpy-in-c

Freeing a NULL pointer

The free() function cause the space pointed to by pointer ptr to be deallocated, that is, made available for further allocations. If the ptr is a NULL pointer, no action occurs.

ptr = NULL ensures that even if you accidently call free(ptr), your program won’t segfault.

This also means that there is no need to put NULL check before freeing, something like -

if (ptr != NULL) free(ptr);

But once the ptr has been freed, it is a good practice to set ptr = NULL. So that you don’t fall in the risk of double-freeing or dangling pointer access.

Please note that although the C standard says it is a no-op, that doesn’t mean that every C library handles it like that. There could be crashes for free(NULL), so it’s best to avoid calling the free() on a pointer which has been set to NULL.

stackoverflow: does-freeptr-where-ptr-is-null-corrupt-memory

Type casting for freeing

const char *a = (const char *)malloc(3);
free(a); // this will be a warning
warning: passing argument 1 of 'free' discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
   31 |     free(a); // this will be a warning
      |          ^
In file included from <source>:3:
/usr/include/stdlib.h:565:25: note: expected 'void *' but argument is of type 'const char *'
  565 | extern void free (void *__ptr) __THROW;

Basically a C language problem. The signature of free() should have been void free(const void *);. Fixed in C++ with delete. You need to cast it to a non-const pointer; free takes a void *, not a const void *.

free(char *(a));

Hex, ASCII and decimal

#include <stdio.h>
#include <string.h>

int main(void)
{
    char a[] = {0x42, 0x31, 0x30, 0x32};
    if(a[3] == '2')
    {
        printf("hex 0x32 is ascii '2', both of which are represented as the same char value\n");
    }
    printf("%s\n", a);
    if(0xff == 0xFF)
    {
        printf("true\n");
    }
    return 0;
}

/*
OUTPUT -

hex 0x32 is ascii '2', both of which are represented as the same char value
B102
true

*/

Clockwise spiral rule

const char *x, x is a pointer to const char. The pointer can change but the contents of the thing (C-style string) being pointed to can not be changed.

char * const x, x is a pointer to a char. The pointer can not be changed, the contents of the string can be changed. In other words, you can change the actual char, but not the pointer pointing to it.

const char *p is a pointer to a const char.
char const *p is a pointer to a char const.

Since const char and char const are the same, it’s the same thing. const will apply to the symbol left of it, if there is none, then, to the symbol right to it.

David Anderson: Clockwise/Spiral Rule

Free the variable that you are passing to a function that internally does strdup

strdup() will malloc a memory and reuturn the pointer of that (where it also copies the supplied C-style string). So, it is the responsibility of the caller function to free this memory after use.

Measuring C programs runtime on linux

$ time ./a.out
real    0m0.003s
user    0m0.000s
sys     0m0.004s
$

stackoverflow: what-do-real-user-and-sys-mean-in-the-output-of-time

Variadic

#include <stdio.h>
#include <stdarg.h>

int sum(int, ...);

int main(void)
{
    printf("Sum of 10, 20 and 30 = %d\n", sum(3, 10, 20, 30));
    printf("Sum of 4, 20, 25 and 30 = %d\n", sum(4, 4, 20, 25, 30));
    return 0;
}

int sum(int num_args, ...)
{
    int val = 0;
    va_list ap;
    int i;

    va_start(ap, num_args);
    for (i = 0; i < num_args; i++)
    {
        val += va_arg(ap, int);
    }
    va_end(ap);

    return val;
}

/*
OUTPUT -

Sum of 10, 20 and 30 = 60
Sum of 4, 20, 25 and 30 = 79

*/

The C library macro void va_start(va_list ap, last_arg) initializes ap variable to be used with the va_arg and va_end macros. The last_arg is the last known fixed argument being passed to the function i.e. the argument before the ellipsis. This macro must be called before using va_arg and va_end.

Following is the declaration for va_start() macro.

void va_start(va_list ap, last_arg);

ap - This is the object of va_list and it will hold the information needed to retrieve the additional arguments with va_arg.

Function overloading not in C, cannot set default value for last parameter in function def in C

C does not allow default value to be set for a parameter(last parameter) in a function. However, there is a trick to achieve the same for on parameter using variadic function. Write a varargs function and manually fill in default values for arguments which the caller doesn’t pass.

Also, ther is no function overloading in C (but it is supported in Modern C, see C11).

Printing byte (hex) values

#include <stdio.h>
#include <string.h> // for memcmp

int main(void)
{
    char buff[3] = { 0, };
    snprintf(buff, 3, "%d", 10);
    printf("%s", buff);

    unsigned char *a = "\xF0";
    unsigned char b = 0xF0;

    if (memcmp(a, (unsigned char *)"\xF0", sizeof(unsigned char)) == 0)
    {
        printf("\nworks");
    }
    printf("\n%02X", b);
    printf("\n%02X", a);
    printf("\n%02X", a[0]);
    return 0;
}

/*
OUTPUT -

10
works
F0
40200A
F0

*/

char [] and char *

#include <stdio.h>

int main(void)
{
    char a[] = "abcdefghij";

    printf("\nsizeof(a) = %d", sizeof(a));

    char *b = "abcdefghij";
    printf("\nsizeof(b) = %d", sizeof(b));
    printf("\nb[0] = '%c'", b[0]);
    printf("\nsizeof(b)/sizeof(b[0]) = %d", sizeof(b) / sizeof(b[0]));

    return 0;
}

/*
OUTPUT -

sizeof(a) = 11
sizeof(b) = 8
b[0] = 'a'
sizeof(b)/sizeof(b[0]) = 8

*/

Checking memleak with valgrind

The below program (filename: strdup_memleak.c) is free of mem-leak.

#include <stdio.h>
#include <string.h>
#include <malloc.h>

int main(void)
{
    char **arr = (char **)calloc(3, sizeof(char *));
    printf("\n%ld sizeof char *\n", sizeof(char *));

    arr[0] = strdup("apple");
    arr[1] = strdup("bye");
    arr[2] = "jo";

    free(arr[0]);
    free(arr[1]);
    free(arr);

    return 0;
}

/*
OUTPUT and method to run -

devpogi@Pavilion Downloads]$ gcc strdup_memleak.c 
[devpogi@Pavilion Downloads]$ ./a.out 

8 sizeof char *
[devpogi@Pavilion Downloads]$ valgrind --leak-check=yes ./a.out 
==13263== Memcheck, a memory error detector
==13263== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==13263== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==13263== Command: ./a.out
==13263== 

8 sizeof char *
==13263== 
==13263== HEAP SUMMARY:
==13263==     in use at exit: 0 bytes in 0 blocks
==13263==   total heap usage: 4 allocs, 4 frees, 1,058 bytes allocated
==13263== 
==13263== All heap blocks were freed -- no leaks are possible
==13263== 
==13263== For lists of detected and suppressed errors, rerun with: -s
==13263== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
[devpogi@Pavilion Downloads]$ 

*/

libcheck header file and its compiled src file on linux

[devpogi@Pavilion ~]$ sudo pacman -S check

[devpogi@Pavilion ~]$ cd /usr/lib
[devpogi@Pavilion lib]$ ls | grep check
libcheck.so
libcheck.so.0
libcheck.so.0.15.2
[devpogi@Pavilion lib]$ 
[devpogi@Pavilion lib]$ cd ../include/
[devpogi@Pavilion include]$ pwd
/usr/include
[devpogi@Pavilion include]$ ls | grep check
check.h
[devpogi@Pavilion include]$ 

stackoverflow: how-to-determine-if-platform-library-is-static-or-dynamic-from-autotools

switch only works on integral values, not pointers

error: switch quantity not an integer
error: pointers are not permitted as case values

switch statements operate on integral values only. That’s why the error message is “switch quantity not an integer”. It’s not a technical limitation so much as it’s outside the language syntax.

switch is a generalization of a jump table. Jump tables are indexed with integers, not pointers. If your case labels are too spread out the compiler probably converts most or all of them to if/else. There’s no benefit from using switch/case with non-integral labels instead of if/else.

stackoverflow: why-no-switch-on-pointers

Error: dereferencing pointer to incomplete type

generic_linkedlist_node *hhhead = generic_linkedlist_get_head_node(generic_linkedlist_instance_obj);
// --snip--
if(hhhead)
{
    free(hhhead->data);
    /*
     * One of my functions calloc'ed it so I will have to free it.
     * It is not the responsibility of generic_linkedlist functions to free it.
     * The above line will show error dereferencing pointer to incomplete type 
     * because the compiler only knows that generic_linkedlist_node is a struct 
     * (typedef'ed in one of the generic_linkedlist header files).
     * Since the members of generic_linkedlist_node struct are "defined" 
     * in .c file and we include only the .h fle, 
     * so compiler won't have any account of 
     * what data members are present in generic_linkedlist_node.
     */
}

NOTE: whoever allocates a memory should free it. It is not the responsibility of some other function to free. If one of “your” functions allocated it, then same/another of “your” functions should deallocate it.

Either define the struct (not just typedef it) in the .h file or have some methods in the .c file to return the data members.

static void myfunc(generic_linkedlist_node *node, void *arg)
{
    cstm_st_type *dddata = (cstm_st_type *)generic_linkedlist_get_data(node);
    
    /* hhhead->data is of generic void * type when the library function returns, 
     * but since we calloc'ed it as cstm_st_type, we type cast into it.
     */

    free(dddata->info);
    /* dddata->info was also calloc'ed from one of my functions.
     */

    free(dddata);
    /* dddata was also calloc'ed from one of my functions.
     */
}

generic_linkedlist_node *hhhead = generic_linkedlist_get_head_node(generic_linkedlist_instance_obj);
if(hhhead)
{
    generic_linkedlist_iterate_node(generic_linkedlist_instance_obj, hhhead, myfunc, NULL); 
    
    // second last argument is a callback function
    // last argument is the arguments passed to callback func
}

strcmp() and strncmp()

#include <stdio.h>
#include <string.h>

int main(void)
{
    char *a = "1";
    char *b = "150";
    if (strncmp(a, b, strlen(a)) == 0)
    {
        printf("WRONG ANSWER! The strings are not equal\n");
        printf("string a can be a substring of string b\n");
        printf("third arg should be the greater of two str len\n");
    }
    if (strcmp(a, b) == 0)
    {
        printf("CORRECT ANSWER!\n");
    }
    return 0;
}

/*
OUTPUT -

WRONG ANSWER! The strings are not equal
string a can be a substring of string b
third arg should be the greater of two str len

*/

Therefore, we should compare till max(strlen(a), strlen(b)) .

Why typedef can not be used with static ?

For example, the code below gives an error -

typedef static int INT2;

The static keyword is not part of the type, depending on the context it is a storage or scope specifier and has no influence whatsoever on the type. Therefore, it cannot be used as part of the type definition, which is why it is invalid here.

A typedef is a type definition, i.e. you’re saying ‘this name’ now refers to ‘this type’, the name you give must be an identifier as defined by the language standard, the type has to be a type specifier, i.e. an already named type, either base type or typedef’ed, a struct, union, or enum specifier, with possible type qualifiers, i.e. const, or volatile.

The static keyword however does not change the type, it says something about the object, (in general, not in the OOP sense), example, it is a variable that is placed in the static storage, not the type.

stackoverflow: why-typedef-can-not-be-used-with-static

Empty string

#include <stdio.h>
#include <string.h>

int main(void)
{
    char *a = "";
    printf("%d\n", strlen(a));
    printf("%s_SUFFIX\n", a);
    return 0;
}

/*
OUTPUT -

0
_SUFFIX

*/

Variably modified array at file scope

#include <stdio.h>
#define N_VALS sizeof(values)/sizeof(values[0])
static int values[] = {1, 2 , 4, 5, 7};

static int n_values = sizeof(values)/sizeof(values[0]);

static int new_values[N_VALS];

static int other_values[n_values];

int main(int argc, char *argv[])
{
        return 0;
}

/* COMPILE ERROR

error: variably modified 'other_values' at file scope
    9 | static int other_values[n_values];
*/

The problem is for other_values not new_values. sizeof is calculated at compile time, but the value of the n_values is evaluated at the run time.

So if a= 5; then the value of a is evaluated at runtime? Or the compiler substitutes it everywhere beforehand? If it’s not removed by the optimization phase of the compiler, yes it is evaluated at the runtime. That means we shouldn’t take that for granted. We can assume it is evaluated at runtime.

static declaration of a function

A function declaration (prototype or even the definition) can omit the keyword static if it comes after another declaration of the same function with static. If there is one static declaration of a function, its first declaration has to be static.
And a reminder: a function definition serves as a prototype; a prototype serves as a declaration.
Normally you will and should have the static in the prototypes too (because they usually come first).

stackoverflow: does-a-static-function-need-the-static-keyword-for-the-prototype-in-c

Supported C/C++ versions by gcc compiler

gcc -v --help 2>/dev/null | grep std=

This will print all the supported C/C++ versions by the compiler. Example output -

  -std=c++11                  Conform to the ISO 2011 C++ standard.
  -std=c++14                  Conform to the ISO 2014 C++ standard.
revised by the 2003 technical corrigendum.
  -std=c11                    Conform to the ISO 2011 C standard.
  -std=c2x                    Conform to the ISO 202X C standard draft (experimental and incomplete support).

How to pass a struct member to sizeof without using a variable?

Let’s say you wanted to use the size of a member of a struct as a buffer size for some other variable/struct but don’t want to create an unnecessary variable of the former struct.

One way is to use a macro for the buffer size of both the struct member and the other variable. Example -

#define BUFFER_SIZE 120

typedef struct _mystruct
{
    char name[BUFFER_SIZE];
} mystruct;

char other_name[BUFFER_SIZE] = {0,};

However, if you cannot change the struct definition, then you could use something like -

typedef struct _mystruct
{
    char name[120];
} mystruct;

char other_name[sizeof(((mystruct *)0)->name)] = {0,};

sizeof(((mystruct *)0)->name) is same as sizeof(((mystruct *)NULL)->name)

Dereferencing doesn’t take place inside sizeof operator. sizeof operator only sees the type of the operand.

sizeof infers the type of ((mystruct *)0)->name, and returns the size of that type. ((mystruct *)0) is just a null pointer of the struct mystruct. 0->name is (at compile time) an expression whose type is that of the member name.

The code within the sizeof never runs (if it did, the program would segfault!). Only the type of value within the sizeof is looked at.

stackoverflow: sizeof-single-struct-member-in-c

Warning: function declaration isn’t a prototype [-Wstrict-prototypes]

int myfunc();

warning: function declaration isn't a prototype [-Wstrict-prototypes]
   11 | int myfunc();
      | ^~~

A prototype is by definition a function declaration that specifies the type(s) of the function’s argument(s).

A non-prototype function declaration like int myfunc(); is an old-style declaration that does not specify the number or types of arguments.

You can call such a function with any arbitrary number of arguments, and the compiler isn’t required to complain but if the call is inconsistent with the definition, your program has undefined behavior.

Logically, empty parentheses would have been a good way to specify that a function takes no arguments, but that syntax was already in use for old-style function declarations, so the ANSI C committee invented a new syntax using the void keyword int myfunc(void);

A function definition (which includes code for what the function actually does) also provides a declaration.

So if you have something like this -


int myfunc()
{
    return 1;
}

This provides a non-prototype declaration int myfunc(); As a definition, this tells the compiler that testlib has no parameters, but as a declaration, it only tells the compiler that testlib takes some unspecified but fixed number and type(s) of arguments.

If you change () to (void) the declaration becomes a prototype.

The advantage of a prototype is that if you accidentally call testlib with one or more arguments, the compiler will diagnose the error.

stackoverflow: warning-error-function-declaration-isnt-a-prototype

Nested array initialization

#include <stdio.h>

typedef struct _mystruct
{
    int s_arr[4];
    int number;
} mystruct;

int main(void)
{
    int arr[4][3] = {
        {1, },
        {2, 1, }, 
        { [2]=4},
    };

    for(int i = 0; i<4; i++)
    {
        printf("arr[%d] = ", i);
        for(int j = 0; j<3; j++)
        {
            printf("%d ", arr[i][j]);
        }
        printf("\n");
    }
    printf("\n");
    mystruct obj[] = {{.s_arr[2] = 3}};

    for(int i = 0; i<4; i++)
    {
        printf("obj[0].s_arr[%d] = %d\n", i, obj[0].s_arr[i]);
    }
    

    return 0;
}

/*
OUTPUT -

arr[0] = 1 0 0 
arr[1] = 2 1 0 
arr[2] = 0 0 4 
arr[3] = 0 0 0 

obj[0].s_arr[0] = 0
obj[0].s_arr[1] = 0
obj[0].s_arr[2] = 3
obj[0].s_arr[3] = 0

*/

cppreference: array_initialization

The order of init for members of a struct doesn’t matter in C

#include <stdio.h>

typedef struct _mstruct
{
    int a[3];
    int b;
    char *c;
} mstruct;

int main(void)
{
    mstruct obj = {.b = 4, .a = {1, 2, }, .c = "Hi"};
    return 0;
}

This compiles without error. However, the same approach in C++ gives an error -

source>: In function 'int main()':
<source>:12:52: error: designator order for field '_mstruct::a' does not match declaration order in 'mstruct' {aka '_mstruct'}
   12 |     mstruct obj = {.b = 4, .a = {1, 2, }, .c = "Hi"};
      |  

stackoverflow: non-trivial-designated-initializers-not-supported

C version used by compiler

printf("C version = %ld\n", __STDC_VERSION__);

This may output something like - C version = 201710

However, if you were to use a compiler flag like this - --std=c11 , you will get output like - C version = 201112

snprintf used with sizeof and strlen

#include <stdio.h>
#include <string.h>

int main(void)
{
    char n1[4] = {'0', '0', '0', '\0'};
    char n2[4] = {'0', '0', '0', '\0'};

    snprintf(n1, sizeof(n1), "%s", "aaa"); // 4 bytes (because allocated space is 4) including '\0'
    snprintf(n2, strlen(n2), "%s", "aaa"); // 3 bytes (because len is 3) including '\0'

    printf("n1 = *****%s*****\n", n1);
    printf("n2 = *****%s*****\n", n2);
    return 0;
}

/*
OUTPUT -

n1 = *****aaa*****
n2 = *****aa*****

*/

Initialize a char array from a string

char arr[] = "ABCDE";

A function with bool argument accepts a string

#include <stdio.h>
#include <stdbool.h>

int get_func(bool value)
{
    if(value) return 1;
    return 0;
}

int main(void)
{
    printf("%d\n", get_func("10")); // string "10" is a char ptr which is implicitly converted to bool to represent true value
    
    printf("%d\n", get_func(NULL)); // NULL ptr is implicitly converted to bool to represent false value
    return 0;
}

/*
OUTPUT -

1
0

*/

stackoverflow: why-a-function-with-bool-argument-accepts-string