---
tags: notes, c, functions, pitfalls
---
# C: Encountered Pitfalls
### `scanf(%s, str)` vs `fgets(str, n, stdin)`
ref: https://hackmd.io/iXozH4iGSj6EYkCL_dBLjg?view
<p> </p>
### `strcmp(char* s1, cha* s2)`
* `strcmp(NULL, s2)`: for either `s1` or `s2` being `NULL`, it becomes an undefined action and may cause fata error to crash.
* If either `s1` or `s2` does not end with `\0`, then the funciton has an undefiend behavior. It may not terminate. Use `strncmp(char *s1, char *s2, size_t n)` instead. It terminates either it reaches `\0` or `n` characters have be compared.
* If `\0` is appeared in the middle of either `s1` or `s2` and you still want to compare the charcters after `\0`, use `memcmp(void *s1, void *s2, size_t n)` instead.
<p> </p>
### `memset(void* _Dst, int _Val, size_t _Size)`
This function works on byte, which means the unit of the parameter `_Size` is byte. So the correct way to use this function is
```C
memset(destination_pointer, value, sizeof(elementType)*counts);
```
This byte usage is not only for `memset()` but for the `mem...()` family such as `memcpy()`, `memicmp()`..., where the parameter `size_t _Size` is applied.
Example snippet:
```c
char x[]={'a', 'b', 'c', 'd', 'e'};
memset(x, 'k', 5);
for(int i=0; i<5; i++)
printf("%c", x[i]); // this prints "kkkkk"
int y[]={1, 2, 3, 4, 5};
memset(y, -1, 5);
for(int i=0; i<5; i++)
printf(" %d", y[i]); // this prints " -1 255 0 0 0"
// the correct way to use memset
memset(y, -1, sizeof(int)*5);
for(int i=0; i<5; i++)
printf(" %d", y[i]); // this prints " -1 -1 -1 -1 -1"
```
### `free(void* ptr)`
* `free(NULL)` is considered as an no-op now days.
* After `free(ptr);`, the following should be `ptr=NULL;`. Because freeing the same pointer twice could be dangerous.
* If `free(ptr)` where `ptr` is not in *heap*, which means it's not assigned by `malloc()`, `callor()` or `realloc()`, the program is possibly to crash.
ex:
```c
char* i=malloc(10*sizeof(char));
free(i); //program works fine.
char* str="hello"; //literal constant
free(str); //program crashes here.
char* str=ctime(time_t *t); //ctime() returns a string of time
free(str); //due to the spacce of the string ctime returns is not assigned by malloc() or its families functions,
//↑↑↑program crashes here
```
* `SIGTRAP`: After N size of memory is allocated, you are probably able to write something into the place over the area you just required(allocated) for. But when you try to free the pointer, the thread will receive a `SIGTRAP` with `gdb`. Note that the program executes normally and returns 0 most of the time because the memory is sufficient. However, it's dangerous to access the memory where it's not declared nor allocated. Freeing the pointers and excuting in `gdb` is a good way to examine if you have unexpected access to the memory.
```c
char* str_ptr=calloc(5, sizeof(char)); // required an memory area of 5 characters
// note that there are 5 char in "hello" but it takes 6 char to store due to '\0'
str_ptr="hello";
// you probably print "hello"\n, it shows that str_ptr[5] is writen as '\0'
printf("%s\n", str_ptr);
// debuggin with gdb, the thread will receive a SIGTRAP
free(str_ptr);
```
### `sizeof()` and `strlen(const char *str)`
`sizeof()` is a compile time operator, while `strlen()` is a runtime function.
* `sizeof(type)` returns how many bytes does the type takes. ex: in most of the platforms, `sizeof(char)==1` and `sizeof(int)==4`.
* `sizeof(array)` returns how many bytes of a size-fixed array.
* example snippet:
```c
int i; sizeof(i); //=4
int j[7]; sizeof(j); //=28
char* str="hello";
sizeof(str); //=8, the size of a char pointer is 8.
strlen(str); //=5, 5 characters in str.
char arr[]="hello";
sizeof(arr); //=6, 6 bytes for 6 char, including '\0'
strlen(arr); //=5, characters counts untill '\0'.
```
### Declartion of `char*` and `char []`
```c
char arr[]="hello"; //this would be in data, stack or heap.
char* ptr ="hello"; //this would be in text(ROM)
arr[1]='i'; //programs works fine.
ptr[1]='i'; //programs crashes due to read-only memory overwrting.
```
### `#include` successfully but failed to call functions
`gcc` can compile and assemble source files seperately into indiviual obeject files and link them together. Finally, an excutable binaray.
You may have the path of `yourLib.h` specified, so nothing goes wrong with
```c
#include <yourLib.h>
```
But when you call any function from `yourLib.h`, the function will be undefined to compiler.
```c
int main(){
func_from_yourLib();
}
```
It's because `gcc` knows where the header file `yourLib.h` is, but doesn't know where the implementaion source `yourLib.c` is.
Besides specifying paths of header files(libraries), you also have to specify paths of source codes with `-L`.