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.
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
(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).
insertAtBeginningOfLinkedList()
head = insertAtBeginningOfLinkedList(head, data)
insertAtBeginningOfLinkedList(Node **head, int data)
main()
) is already a pointer to Node
, passing by reference can also be like insertAtBeginningOfLinkedList(&head, data)
*head
, example, if (*head != NULL) temp->next = *head;
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
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
NULL
pointerThe 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 free
ing, 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
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));
#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
*/
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
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.
$ 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
#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
.
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).
#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
*/
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]$
*/
[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 pointerserror: 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
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))
.
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
#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
*/
#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 functionA 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
gcc
compilergcc -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).
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
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
#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
#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
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*****
*/
char
array from a stringchar arr[] = "ABCDE";
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