C/C++ Essentials
- In C and C++ the single quote is used to identify the single character, and double quotes are used for string literals.
Don't get confused
#include <stdio.h> // in c
#include <iostream> // in c++
int main(int argc, char **argv, char **envp)
// OR Both are the same !!
int main(int argc, char *argv[], char *envp[])
Data Pointers
-
pointers stores address (&var, "STR", FunName, ArrayName, AnotherPointerName)
- accessed by using * before it or using [] after
-
you can increament it's values or decrement it
p[i] === *(p+i) -
arr === &arr === &(arr[0]), all points to the same location/addr. -
casting,
(int*)p === &p[0] char *str; === char str[];
int a; // declaring a varibale
int *p; // pointer that points to an integer
char *p = "CBA";
p = "HII"; // make the pointer points to the first char of this new str
printf("%s\n", p); // HII
// we can pass a string (array of char) to a poiner of type char
void print(char *p){
printf("%s\n", p); // passing an addr of the string to %s (the same for %n)
printf("%c\n", *p); // passing a value of type char to %c (the same for %d, %i, %u, %x, %o, ..)
}
int main(){
print("ABC");
}
int a = 10;
int *p1 = &a;
printf("%p ==> %p\n", p1, p1+1); // 0x7ffc32680e84 ==> 0x7ffc32680e88 the addr incremented by 4 bytes
char *s = "ABC"; // stored in the .text section !!
char *p2 = s;
printf("%p ==> %p\n", p2, p2+1); // 0x563472a48013 ==> 0x563472a48014 the addr incremented by 1 byte
General Purpose Pointer
is a pointer that is not associated with any data types. It points to some data location in the storage.
As we all know, the address that is assigned to any pointer must have the same data type as we have specified in the declaration of the pointer. For instance, when we are declaring the float pointer, this float pointer won't be able to point to an int variable or any other variable. In simpler words, it will only be able to point to the float type variable. We thus use a void pointer to overcome this problem.
In 16-bit systems, the size of a void pointer is 2 bytes. In 32-bit systems, the size of a void pointer is 4 bytes. In 64-bit systems, the size of a void pointer is 8 bytes.
// functions prototype
void *malloc(size_t size);
void *calloc(size_t nmemb, size_t size);
// Ex1
int x = 52;
void *p = &x;
// Ex2
char *p = malloc(10);
EX
#include<stdlib.h>
int main() {
int g = 83;
float h = 4.9;
void *m;
m = &h;
printf("\nThe Float in this program is = %f", *( (float*) m) );
m = &g;
printf("The Integer in this program is = %d", *( (int*) m) );
return 0;
}
Function Pointers
- function pointer points to code, not data
- we do not allocate de-allocate memory using function pointers
int foo(int); // declaring a function, with one argument of type int and a return value of type int
int *foo(int); // declaring a function, with one argument of type int and a return value of type int*
int (*foo)(int); // declaring a pointer to a (function with one argument of type int and a return value of type int)
// foo is the name of the pointer !!
void fun(int a){
printf("Value of a is %d\n", a);
}
int main(){
// fun_ptr is a pointer to function fun()
void (*fun_ptr)(int) = &fun;
//The above line is equivalent of following two
void (*fun_ptr)(int);
fun_ptr = &fun;
// OR
fun_ptr = fun;
// Invoking fun() using fun_ptr
(*fun_ptr)(10);
// OR
fun_ptr(10);
return 0;
}
kowing this we can declare an Array Of Function Pointers, and we can Pass Function to Another Function, see here.
Structs
Nothing called classes in C, it's just Structs.
also you should know that we can't define a function inside the struct directly !! but you can emulate the same thing using function pointers and explicitly passing the "this" parameter :
struct myStructure {
int n; // 0x4 bytes
char *name; // 0x4
int (*FunPtr)(); // 0x4 bytes
}; // total size = 0xc
// 0x565561d7 <main+15> sub esp, 0x10 // allocate some memory (in the stack) !!
void fun(){
printf("I am a funny");
}
int main(){
struct myStructure S1; // 0x565561d7 <main+15> sub esp, 0x10
S1.n = 10; // 0x565561e4 <main+28> mov dword ptr [ebp - 0x14], 0xa
S1.name = "O54ma"; // 0x565561f1 <main+41> mov dword ptr [ebp - 0x10], edx // EDX 0x56557015 ◂— 'O54ma'
S1.FunPtr = fun; // 0x565561fa <main+50> mov dword ptr [ebp - 0xc], edx <fun> // EDX 0x5655619d (fun) ◂— push ebp
printf("%d === %s === ", S1.n, S1.name);
S1.FunPtr(); // 0x5655621c <main+84> call eax // EAX 0x5655619d (fun)
}
// stdout
// 10 === O54ma === I am a funny
Dynamic Allocation
There's no new/delete expression in C.
The closest equivalent are the malloc and free functions, if you ignore the constructors/destructors and type safety.
all the dynamic allocation functions (new in c++ / malloc in C) return the address of the allocated block.
if an operator or function “returns a pointer.” what it’s really doing is returning a memory address whose data type is a pointer to something. A pointer variable is not being returned … just an address
struct myStructure {
int n; // 0x4 bytes
char *name; // 0x4 bytes
int (*FunPtr)(); // 0x4 bytes
}; // total size = 0xc
void fun(){
printf("I am a funny");
}
int main(){
struct myStructure *S1; // just a pointer !!
S1 = (struct myStructure*) malloc(sizeof(struct myStructure)); // 0x565561fa <main+34> call malloc@plt // After The execution ==> EAX 0x5655a1a0 ◂— 0x0
// 0x5655a1a0 on the [heap] !!!
// 0x56556202 <main+42> mov dword ptr [ebp - 0xc], eax // EAX 0x5655a1a0 ◂— 0x0
S1->n = 10; // 0x56556208 <main+48> mov dword ptr [eax], 0xa
S1->name = "O54ma"; // 0x56556217 <main+63> mov dword ptr [eax + 4], edx // EDX 0x56557015 ◂— 'O54ma'
S1->FunPtr = fun; // 0x56556223 <main+75> mov dword ptr [eax + 8], edx // EDX 0x565561ad (fun) ◂— push ebp
printf("%d === %s === ", S1->n, S1->name);
// 0x56556248 <main+112> mov eax, dword ptr [eax + 8] // After Execution EAX 0x565561ad (fun) ◂— push ebp
S1->FunPtr(); // 0x5655624b <main+115> call eax
free(S1);
}
sys/types.h - data types
for more
u_char // unsigned char
u_int // unsigned int
u_short // unsigned short
u_long // unsigned long
size_t // unsigned long --> Used for sizes of objects.
ssize_t // signed long --> Used for a count of bytes or an error indication
pid_t // signed integer --> Process IDs and process group ids
...
...
...
ip_addr_t // nice ^^
Stream in C
the stream is just a generic name, used as a uniform way of interfacing with different sources of sequential data, like files, sockets, keyboards, USB ports, printers or whatever.
// prototype
int fputs(const char *s, FILE *stream); // stream here is a pointer to a file object
FFlush Stdin & Stdout
The operating system may initially put the output data in a temporary buffer before writing it to an output stream or FILE like stdout.
Buffering works in such a way that the contents of an output buffer are only written to the stdout stream or FILE object once the buffer is full, or there is a new line character at the end of it
fflush function make sure that the current state of the temporary buffer is immediately printed to the console and written to the stdout stream.
#include <stdio.h>
int main()
{
printf("HII"); // the string may not be printed cuz the temporary buffer not filled yet
fflush(stdout); // flush the toilet
}
why flusing the stdin ??
in the example below the scanf reads string up to newline and add it into the tmp buffer, after entering the second loop the scanf won't accept any input, since the tmp buffer not empty yet (never saw a newline), so in this case we force the stdin to be flushed to accept new input every time ^^.
int main()
{
char str[20];
int i;
for (i=0; i<2; i++)
{
scanf("%[^\n]s", str); // read up to \n, and \n included !!
printf("%s\n", str);
// fflush(stdin);
}
return 0;
}
flush is only used with output streams.
The most portable solution for flushing stdin would probably be something along the lines of the following:
// fflush(stdin);
int c;
while ((c = getchar()) != '\n' && c != EOF);
"extern" keyword in C
Extern is a short name for external.
used to declare a global variable without any memory assigned to it. It's used to declare variables and functions in header files. Extern can be used access variables across C files.
https://www.geeksforgeeks.org/understanding-extern-keyword-in-c/
libc common functions
check the manual pages for more information .
System()
int system(const char *command);
The system() library function uses fork() to create a child process that executes the shell command specified in command using execl() as follows:
execl("/bin/sh", "sh", "-c", command, (char *) NULL);
returns after the command has been completed.
Exec()
The exec() family {execl, execle, execlp, execv, ...} of functions replaces the current process image with a new process image.
Tricks
int main(){
char *a = "ABC";
printf("%c", 2[a]); // prints C
// 2[a1] ==> a1[2] ==> (2)[a1] ==> (1+1)[a1]
// ==> (int*)a[2] ==> (int*)*(a+2)
}
int main(){
size_t i = 0; // it's unsigned
printf("%zu\n", i-1); // 0xffffffffffffffff
}
int main(int argc, char **argv){
printf("%s\n", argv['A']); // argv['A'] == argv[65]
}
printf("%lu\n", (unsigned long)n); %zu –> size_t