Part 1
Compilation, structures de contrôle, opérations sur les types, opérations bits-à-bits
Types entiers, casts, et promotion
Before we start, here’s the format of printf()
that might be useful for the following “experiments”:
specifier | Output | Example |
---|---|---|
d or i |
Signed decimal integer | 392 |
u |
Unsigned decimal integer | 7235 |
o |
Unsigned octal | 610 |
x |
Unsigned hexadecimal integer | 7fa |
X |
Unsigned hexadecimal integer (uppercase) | 7FA |
f |
Decimal floating point, lowercase | 392.65 |
F |
Decimal floating point, uppercase | 392.65 |
e |
Scientific notation (mantissa/exponent), lowercase | 3.9265e+2 |
E |
Scientific notation (mantissa/exponent), uppercase | 3.9265E+2 |
g |
Use the shortest representation: %e or %f |
392.65 |
G |
Use the shortest representation: %E or %F |
392.65 |
a |
Hexadecimal floating point, lowercase | -0xc.90fep-2 |
A |
Hexadecimal floating point, uppercase | -0XC.90FEP-2 |
c |
Character | a |
s |
String of characters | sample |
p |
Pointer address | b8000000 |
n |
Nothing printed. The corresponding argument must be a pointer to a signed int . The number of characters written so far is stored in the pointed location. |
|
% |
A % followed by another % character will write a single % to the stream. |
% |
source: http://www.cplusplus.com/reference/cstdio/printf/
question 1: type char
The type char can be signed or un signed.
Here’s a programme which allows us to know whether for a particular environment, the char is signed or not :
void q1()
{
char c=0xFF;
printf("%c\n",c);
if(c==-1) printf("signed\n");
else printf("unsigned\n");
}
It turns out that in the case of my PC, the char is signed.
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part1
�
signed
question 2: int, signed int and unsigned int
int is equivalent to signed int .
The size of these types will depend the development environment. For example, int can be any size >= 16bits.
void q2()
{
int i;
signed int si;
unsigned int usi;
printf("size of a int: %ld bytes\n",sizeof(i));
printf("size of a signed int: %ld bytes\n",sizeof(si));
printf("size of a unsigned int: %ld bytes\n",sizeof(usi));
//the return type of sizeof() function is long unsigned int!
printf("the max value of a (signed)int: %d\n",INT_MAX);
printf("the min value of a (signed)int: %d\n",INT_MIN);
printf("the max value of a unsigned int:%u\n",UINT_MAX);
printf("the min value of a unsigned int:%u\n",UINT_MAX+1);
}
Notice that the return type of sizeof()
is actually long unsigned int, we should use a %ld
instead of %d
for printf()
, otherwise there’d be a compiler error.
Here’s the result for my PC:
1
2
3
4
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part1
size of a int: 4 bytes
size of a signed int: 4 bytes
size of a unsigned int: 4 bytes
Theoretically, if a integral type have n bytes, their max & min value will be:
signed int | unsigned int | |
---|---|---|
max | 2^(8n-1)-1 | 2^8n-1 |
min | -2^(8n-1) | 0 |
The limits.h
header file defines constants with the limits of fundamental integral types for the specific system.
1
2
3
4
the max value of a (signed) int: 2147483647
the min value of a (signed) int: -2147483648
the max value of a unsigned int: 4294967295
the min value of a unsigned int: 0
question 3: _t data type
While the size of int can be different from one computer to another, the size of _t data type (width-specific integral types) is guaranteed:
- int8_t uint8_t : coded on one byte, representing the signed and unsigned values
- int16_t uint16_t : coded on two bytes, representing the signed and unsigned values
- … and so on. ( 32 64 )
But the _t data type are typedef types in the stdint.h
header.
#include <stdint.h>
void q3()
{
uint8_t super,bof,naze,superman,sousleau;
super=0x11;
bof=0b1010;
naze=8;
superman=0b10110;
sousleau=0x2;
printf("super: %d\n",super);
printf("bof: %d\n",bof);
printf("naze: %d\n",naze);
printf("superman: %d\n",superman);
printf("sousleau: %d\n",sousleau);
}
Different ways of integer declaration:
décimal 42
hexadécimal 0x2A
binaire 0b101010.
Cette manière de noter est valide chez GCC mais appartient à une extension GCC râle si l’option-pedantic est indiquée.
1
2
3
4
5
6
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part1
super: 17
bof: 10
naze: 8
superman: 22
sousleau: 2
question 4: long and long long
void q4()
{
long l;
long long ll;
printf("size of a long: %ld bytes\n",sizeof(l));
printf("size of a long long: %ld bytes\n",sizeof(ll));
}
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part1
size of a long: 8 bytes
size of a long long: 8 bytes
Le standard C99 indique qu’un long doit être au moins sur 4 octets, et qu’un long doit être au moins sur 8. Rien de plus n’est spécifié.
question 5: overflow of unsigned char and signed char
Be careful with overflow of capacity
1
2
3
4
5
6
7
void q5()
{
signed char sc=SCHAR_MAX+1;
unsigned char uc=UCHAR_MAX+1;
printf("the max+1 of a signed char: %d\n",sc);
printf("the max+1 of a unsigned char: %d\n",uc);
}
The integral types are coded by 2’s complement:
1
2
3
4
5
6
Part1.c: In function ‘q5’:
Part1.c:53:19: warning: large integer implicitly truncated to unsigned type [-Woverflow]
unsigned char uc=UCHAR_MAX+1;
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part1
the max+1 of a signed char: -128
the max+1 of a unsigned char: 0
question 6: overflow of int
1
2
3
4
5
void q6()
{
int i=INT_MAX+1;
printf("the max+1 of a int: %d\n",i);
}
1
2
3
4
5
6
Part1.c:59:15: warning: integer overflow in expression [-Woverflow]
int i=INT_MAX+1;
^
gcc -o Part1 Part1.o -lm
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part1
the max+1 of a int: -2147483648
question 7: undefined behavior
The overflow of a signed int is a undefined beharvior, while the overflow of a unsigned int is a well-defined behavior.
Expression | Result |
---|---|
UINT_MAX+1 | 0 |
LONG_MAX+1 | undefined |
INT_MAX+1 | undefined |
1«-1 | undefined |
1«0 | 1 |
1«31 | undefined in C99 |
1«32 | undefined |
1/0 | undefined |
1
2
3
4
5
6
void q7()
{
uint32_t a,b= 4000000000,c= 500000000,d=0;
a=(b+c)-d;
printf("a:%d\n",a);
}
205032704=4000000000+500000000-2^32
1
2
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part1
a:205032704
question 8: comparison bewteen signed ant unsigned int
void q8()
{
if (sizeof(int) < -1)
printf("Bizarre, bizarre ... ??\n");
else
printf ("Tout semble normal\n");
}
1
2
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part1
Bizarre, bizarre ... ??
This is becourse that the return type of sizeof()
is long unsigend int, so -1 is automatically casted to a huge positive number.
question 9: floating type
void q9()
{
int i=3.14;
float f=3.14;
double d=3.14;
float lf=3.14159265358979328462264338327;
double ld=3.14159265358979328462264338327;
printf("3.14 int: %d\n",i);
printf("3.14 float: %f\n",f);
printf("3.14 double: %f\n",d);
printf("long float: %f\n",lf);
printf("long double: %f\n",ld);
}
By default, printf(""%f")
will display 7 digits:
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part1
3.14 int: 3
3.14 float: 3.140000
3.14 double: 3.140000
long float: 3.141593
long double: 3.141593
question 10: floating type II
noramalization of a floating type: In the IEEE formats:
Type | Sign | Exponent | Mantissa |
---|---|---|---|
Single(float) | 1 | 8 | 23 |
Double(double) | 1 | 11 | 52 |
-
The IEEE doesn’t use 2’s complement to code the exponent, so if we convert a dicimal number to a IEEE float type, we should add a bias127 for the exponent !
So in the case of a single precision floating, the actual exponent varies between -127 and 128 ! ( 0-127 and 255-127)
-
The MSB of matissa represents 2^-1 and so on…
The formula for the conversion from a IEEE float type to a decimal number is :
Type | Exponent bias | Bits precision (1. is implicit) | Number of decimal digits |
---|---|---|---|
Single(float) | 127 | 24 | ~7.2 |
Double(double) | 1023 | 53 | ~15.9 |
1
2
3
4
5
6
7
8
9
10
11
12
13
void q10()
{
int i=3.14;
float f=3.14;
double d=3.14;
float lf=3.14159265358979328462264338327;
double ld=3.14159265358979328462264338327;
printf("3.14 int: %d\n",i);
printf("3.14 float: %.29f\n",f);
printf("3.14 double: %.29f\n",d);
printf("long float: %.29f\n",lf);
printf("long double: %.29f\n",ld);
}
1
2
3
4
5
6
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part1
3.14 int: 3
3.14 float: 3.14000010490417480468750000000
3.14 double: 3.14000000000000012434497875802
long float: 3.14159274101257324218750000000
long double: 3.14159265358979311599796346854
Notice that for float, the meaningful number of decimal digits is always 7 (including 3.) and for double, the meaningful number of decimal digits is always 15 (including 3.).
question 11: type bool
#include <stdbool.h>
void q11()
{
printf("size of a bool: %ld byte\n",sizeof(bool));
printf("value of true: %d\n",true);
printf("value of false: %d\n",false);
}
1
2
3
4
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part1
size of a bool: 1 byte
value of true: 1
value of false: 0
question 12: addition of char and int
void q12()
{
char mychar = 'A';
int val = mychar + 10;//mychar converted to int before the addition
printf("val = %d char = %c\n", val,val);
}
1
2
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part1
val = 75 char = K
question 13: “false “subtraction de unsigned int
void q13()
{
uint16_t a = 413;
uint16_t b = 64948;
fprintf(stdout, "%u\n", (a - b));
}
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part1
4294902761
The type of the result is clearly not uint16_t, since the max value of a uint16_t is 65535. (seems a implicit conversion from uint16_t to uint32_t took place).
question 14: “right” subtraction de unsigned int
Conversion implicite de type
Si un opérateur a des opérandes de différents types, les valeurs des opérandes sont converties
automatiquement dans un type commun. Lors d’une affectation, la donnée à droite du signe d’égalité
est convertie dans le type à gauche du signe d’égalité. Dans ce cas, il peut y avoir perte de précision
si le type de la destination est plus faible que celui de la source. De même, lors de l’appel d’une
fonction, les paramètres sont automatiquement convertis dans les types déclarés dans la définition
de la fonction.
Dans n’importe quelle expression entière, si un int peut représenter toutes les valeurs de cette
expression (par exemple uint16_t ), alors il est converti implicitement par le compilateur en
int. Si cela ne suffit pas, la conversion est faite vers unsigned int , si possible.
Dans le cas où une opération artithmétique est efectuée entre deux expressions qui n’ont pas le
même type après la conversion entière décrite plus haut, alors la conversion de type continue selon
les règles suivantes :
— si les deux opérandes sont de type flottant, alors l’opérande ayant le rang le plus bas est
converti vers un type de même rang que l’autre opérande, l’ordre des rangs étant définie
comme suit : float -> double -> long double.
— si un seul des opérande est est de type flottant, le type entier est converti dans ce type flottant.
— si les deux opérandes sont de type entier, alors :
— si les deux opérandes sont tous deux de de type non-signé, ou tous deux de type signé,
le type de plus petit rang est converti dans l’autre, la hiérarchie de rang chez les entiers
étant la suivante :
\1. long long int, unsigned long long int
\2. long int, unsigned long int
\3. int, unsigned int
\4. short int, unsigned short int
\5. signed char, char, unsigned char
— sinon si le type Tu d’un des opérande est non signé et a un rang égal ou supérieur au
type T de l’autre opérande, alors T est convertie dans Tu.
— sinon, si le type Ts de l’un des opérande est signé et peut représenter toutes les valeurs
de l’autre opérande, alors T est converti en Ts
— sinon les deux opérandes sont converties dans le type entier non signé correspondant
au type de l’opérande qui a un type signé.
Si une perte de précision est possible lors de la conversion implicite de type, le compilateur peut
génèrer un warning.
Exemples :
int 2 + 3 int 2 + int 3→int 5
double 2.2 + 3.3 double 2.2 + double 3.3 →double 5.5
mix 2 + 3.3 int 2 + double 3.3→double 2.0 + double 3.3→double 5.3
int 1 / 2 int 1 / int 2→int 0
double 1.0 / 2.0 double 1.0 / double 2.0→double 0.5
mix 1 / 2.0 int 1 / double 2.0→double 1.0 / double 2.0→double 0.5
1
2
3
4
5
6
7
void q14()
{
uint16_t a = 413;
uint16_t b = 64948;
uint16_t c=a-b;
fprintf(stdout, "%u\n", c);
}
1
2
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part1
1001
question 15: non correct conversion(mantissa trick!)
1
2
3
4
5
6
7
void q15()
{
long a = 8000000002;
float b = 2;
long c = a / b;
printf("res : %li\n", c);
}
1
2
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part1
res : 4000000000
-
fisrt implicit conversion:
a/b
gives us actually a float, since the number of decimal digits is about 7, a float type is unable to represent correctly 4000000001 ( it’s something like 4000000000.000). -
second implicit conversion:
long c=a/b
conversion from float to long int.
question 16: addition of a float and a long
If we try to add a float and a long, the implicit conversion from long to float will take place.
1
2
3
4
5
6
void q16()
{
long l=142857142857;
float f=0;
printf("l+f : %f\n",l+f);
}
1
2
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part1
l+f : 142857142272.000000
question 17: assignment of a int
If we try to assign a floating value to a int, the “float” will be truncated.
1
2
3
4
5
void q17()
{
int i=1.618;
printf("i : %d\n",i);
}
1
2
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part1
i : 1
Explicit cast
question 19: between int and char
1
2
3
4
5
6
7
8
9
void q19()
{
char c=42;
int i=(char)c;
printf("i: %d\n",i);
i=42;
c=(char)i;
printf("c: %c\n",c);
}
1
2
3
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part1
i: 42
c: *
question 20:
void q20()
{
int i=-42;
unsigned int u=(unsigned int)i;
printf("unsigend int: %u\n",u);
int ii=0x2a3b;
char c=(char)ii;
printf("char : %c\n",c);
}
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part1
unsigend int: 4294967254
char : ;
By reading the ASCII table, ‘;’ corresponds to the hex number 3b. (which takes 1 byte)
question 21:
1
2
3
4
5
6
7
8
9
void q21()
{
char A=3;
int B=4;
float C=A/B;
printf("C: %f\n",C);
C=(float)A/(float)B;
printf("C: %f\n",C);
}
1
2
3
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part1
C: 0.000000
C: 0.750000
Bits-to-bits operations
operation | operator | example |
---|---|---|
shift | >> or « | a=b«5 |
xor | ^ | |
1’s complement | ~ | ~0b0101 = 0b1010 |
and | & | 0b0111&0b1101=0b0101 |
or | | | 0b0001|0b0001=0b1001 |
**&&, | and == are the logical operators** |
question 22
void printRoomsState(uint32_t allRooms)
{
int index=0;
while(index<32){
printf("%d: %d ",index++,allRooms%2);
allRooms%2?
printf("Occupé\n"):printf("Non occupé\n");
allRooms=allRooms>>1;
}
}
int main()
{
printRoomsState(5);
return 0;
}
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part1
0: 1 Occupé
1: 0 Non occupé
2: 1 Occupé
3: 0 Non occupé
4: 0 Non occupé
5: 0 Non occupé
6: 0 Non occupé
7: 0 Non occupé
8: 0 Non occupé
9: 0 Non occupé
10: 0 Non occupé
11: 0 Non occupé
12: 0 Non occupé
13: 0 Non occupé
14: 0 Non occupé
15: 0 Non occupé
16: 0 Non occupé
17: 0 Non occupé
18: 0 Non occupé
19: 0 Non occupé
20: 0 Non occupé
21: 0 Non occupé
22: 0 Non occupé
23: 0 Non occupé
24: 0 Non occupé
25: 0 Non occupé
26: 0 Non occupé
27: 0 Non occupé
28: 0 Non occupé
29: 0 Non occupé
30: 0 Non occupé
31: 0 Non occupé
question 23:
uint32_t roomGoesOccupied(uint32_t allRooms,unsigned int roomNb)
{
uint32_t operand=1<<roomNb;
return operand|allRooms;
}
int main()
{
printRoomsState(roomGoesOccupied(5,24));
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part1
0: 1 Occupé
1: 0 Non occupé
2: 1 Occupé
3: 0 Non occupé
4: 0 Non occupé
5: 0 Non occupé
6: 0 Non occupé
7: 0 Non occupé
8: 0 Non occupé
9: 0 Non occupé
10: 0 Non occupé
11: 0 Non occupé
12: 0 Non occupé
13: 0 Non occupé
14: 0 Non occupé
15: 0 Non occupé
16: 0 Non occupé
17: 0 Non occupé
18: 0 Non occupé
19: 0 Non occupé
20: 0 Non occupé
21: 0 Non occupé
22: 0 Non occupé
23: 0 Non occupé
24: 1 Occupé
25: 0 Non occupé
26: 0 Non occupé
27: 0 Non occupé
28: 0 Non occupé
29: 0 Non occupé
30: 0 Non occupé
31: 0 Non occupé
question 24:
1
2
3
4
5
6
7
8
9
bool isOccupied(uint32_t allRooms,unsigned int roomNb)
{
return (allRooms>>roomNb)%2;
}
int main()
{
printf("%d\n",isOccupied(5,2));
return 0;
}
1
2
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part1
1
question 25:
1
2
3
4
5
6
7
8
9
10
uint32_t roomGoesEmpty(uint32_t allRooms,unsigned int roomNb)
{
uint32_t operand=1<<roomNb;
return (~operand)&allRooms;
}
int main()
{
printRoomsState(roomGoesEmpty(5,0));
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part1
0: 0 Non occupé
1: 0 Non occupé
2: 1 Occupé
3: 0 Non occupé
4: 0 Non occupé
5: 0 Non occupé
6: 0 Non occupé
7: 0 Non occupé
8: 0 Non occupé
9: 0 Non occupé
10: 0 Non occupé
11: 0 Non occupé
12: 0 Non occupé
13: 0 Non occupé
14: 0 Non occupé
15: 0 Non occupé
16: 0 Non occupé
17: 0 Non occupé
18: 0 Non occupé
19: 0 Non occupé
20: 0 Non occupé
21: 0 Non occupé
22: 0 Non occupé
23: 0 Non occupé
24: 0 Non occupé
25: 0 Non occupé
26: 0 Non occupé
27: 0 Non occupé
28: 0 Non occupé
29: 0 Non occupé
30: 0 Non occupé
31: 0 Non occupé
Create a type
Enumeration
If we want to typedef a enum:
1
2
enum scrutin_e {MAJORITAIRE_UNI, MAJORITAIRE_PLURI, PROPORTIONNEL, MIXTE};
typedef enum scrutin_e scrutin_t;
question 29: Different ways to declare a enum
1
2
3
4
5
6
7
8
9
void q29()
{
enum scrutin_e1 {MAJORITAIRE_UNI1,MAJORITAIRE_PLURI1,PROPORTIONNEL1,MIXTE1};
printf("scrutin_e1: %d %d %d %d\n",MAJORITAIRE_UNI1,MAJORITAIRE_PLURI1,PROPORTIONNEL1,MIXTE1);
enum scrutin_e2 {MAJORITAIRE_UNI2=2,MAJORITAIRE_PLURI2=8,PROPORTIONNEL2=42,MIXTE2=12};
printf("scrutin_e2: %d %d %d %d\n",MAJORITAIRE_UNI2,MAJORITAIRE_PLURI2,PROPORTIONNEL2,MIXTE2);
enum scrutin_e3 {MAJORITAIRE_UNI3=4,MAJORITAIRE_PLURI3,PROPORTIONNEL3,MIXTE3};
printf("scrutin_e3: %d %d %d %d\n",MAJORITAIRE_UNI3,MAJORITAIRE_PLURI3,PROPORTIONNEL3,MIXTE3);
}
- Notice that the STRINGs of enums can’t be the same even if they are defined in different enums.
- We don’t need to declare a enum variable to use its value.
1
2
3
4
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part1
scrutin_e1: 0 1 2 3
scrutin_e2: 2 8 42 12
scrutin_e3: 4 5 6 7
question 30:
1
2
3
4
void q30()
{
enum semaine {LUNDI=1,MARDI,MERDREDI,JEUDI,VENDREDI,SAMEDI,DIMANCHE};
}
Switch-case
question 31:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
void appreciate(int note)
{
switch (note) {
case 12:
printf("12 ! Passable ");
break;
case 18:
printf("18 ! Super ! ");
case 6:
printf("6 ! Naze ");
break;
case 8:
printf("8 ! Mieux que naze ");
break;
case 10:
printf("10 ! Presque passable ");
break;
default:
printf("%d ! Pas prevu par le de-qui-corrige", note);
break;
}
printf("\n");
}
int main()
{
appreciate(6);
appreciate(12);
appreciate(18);
appreciate(14);
return 0;
}
1
2
3
4
5
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part1
6 ! Naze
12 ! Passable
18 ! Super ! 6 ! Naze
14 ! Pas prevu par le de-qui-corrige
- Since there’s no
break
for the case of 18, the following cases are also excuted till we meet abreak
- But the
break
of the default case is not necessary.
question 32:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
void q32(int n)
{
if(!n){
printf("Ga\n");
}
while(n>0){
switch(n%4){
case 0:
printf("Ga ");
break;
case 1:
printf("Bu ");
break;
case 2:
printf("Zo ");
break;
case 3:
printf("Meu ");
}
n/=4;
}
printf("\n");
}
int main()
{
q32(3);
q32(6);
q32(11);
q32(42);
return 0;
}
1
2
3
4
5
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part1
Meu
Zo Bu
Meu Zo
Zo Zo Zo
Part 2
pointer, array, static allocation, parametered main function
Dereference & acces to an address
question 1: address of main()
1
2
3
4
int main();
void q1(){
printf("%p\n",&main);
}
1
2
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part2
0x565247308e65
The main()
belongs to the Text segment(read only)
question 2 3 4: address of the global variables
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int intNotInitialized;
int intInitialized=0;
void q2(){
intNotInitialized=42;
intInitialized=5;
int* addresseNot=&intNotInitialized;
int* addresseInit=&intInitialized;
printf("la valeur de intNotInitialized: %d\n",intNotInitialized);
printf("l'addresse de intNotInitialized:%p\n",addresseNot);
printf("la valeur de intInitialized: %d\n",intInitialized);
printf("l'addresse de intInitialized: %p\n",addresseInit);
*addresseNot=43;
*addresseInit=6;
printf("après la modification:\n");
printf("la valeur de intNotInitialized: %d\n",intNotInitialized);
printf("la valeur de intInitialized: %d\n",intInitialized);
}
The global variables are located in the BSS segment
1
2
3
4
5
6
7
8
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part2
la valeur de intNotInitialized: 42
l'addresse de intNotInitialized:0x55daf5c0c018
la valeur de intInitialized: 5
l'addresse de intInitialized: 0x55daf5c0c014
après la modification:
la valeur de intNotInitialized: 43
la valeur de intInitialized: 6
question 5: address of the local variables
1
2
3
4
5
6
7
8
void q5(){
int localeNot;
int localeInit=0;
printf("la valeur de localeNot: %d\n",localeNot);
printf("l'addresse de localeNot: %p\n",&localeNot);
printf("la valeur de localeInit: %d\n",localeInit);
printf("l'addresse de localeInit: %p\n",&localeInit);
}
The local variables are located in the stack.
1
2
3
4
5
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part2
la valeur de localeNot: -754673785
l'addresse de localeNot: 0x7ffc36a7ab70
la valeur de localeInit: 0
l'addresse de localeInit: 0x7ffc36a7ab74
The value of a non initialized local variable is actually the value which already exists before the program excute, while a non initialized globle int is 0.
Array
question 6: sizeof()
1
2
3
4
5
6
7
8
9
void q6(int size){
int all_elements[size];
printf("%ld\n",sizeof(all_elements));
}
int main(int argc,char * argv[]){
int number_of_elements=atoi(argv[1]);
q6(number_of_elements);
return 0;
}
sizeof()
is a operator just like + - * are.
1
2
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part2 10
40
sizeof()
applied on a array, returns the number of bytes occupied by this array.<
question 7: define a new array type
-
define MAX_SIZE with unsigned int:
1 2
unsigned int MAX_SIZE=5; typedef int matrix [MAX_SIZE][MAX_SIZE];causes a compiler error:
causes a compiler error
1 2
Part2.c:11:13: error: variably modified ‘matrix’ at file scope typedef int matrix [MAX_SIZE][MAX_SIZE];
-
define MAX_SIZE with const unsigned int:
1 2
const unsigned int MAX_SIZE=5; typedef int matrix [MAX_SIZE][MAX_SIZE];
also causes a compiler error:
1 2
Part2.c:11:13: error: variably modified ‘matrix’ at file scope typedef int matrix [MAX_SIZE][MAX_SIZE];
-
define MAX_SIZE with a maro:
1 2 3
#define MAX_SIZE 5 typedef int matrix [MAX_SIZE][MAX_SIZE]; //order of [][] and "matrix"!
this kind of definition works
question 8:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void q8(int (*a)[5],int size){
//int (*a)[5]: a pointer which points an array containing 5 int
//int *a [5]: a array which contains 5 pointer of int
for(int i=0;i<size;i++){
for(int j=0;j<size;j++){
printf("%d ",a[i][j]);
}
printf("\n");
}
}
int main(int argc,char * argv[]){
matrix mymatrix;
q8(mymatrix,MAX_SIZE);
return 0;
}
It’s imfortant ot distinguish the differents meaning of declarations of a complex array type:
int (*a)[5]
: a pointer which points an array containing 5 intint *a [5]
: a array which contains 5 pointer of int
1
2
3
4
5
6
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part2
0 0 1935634848 32764 -1
0 0 0 1935663720 32764
-998836464 32594 0 0 0
0 0 0 1970169159 0
9 0 -1001093536 32594 1935635000
It’s normal that some values of the mymatrix seem to be random: mymatrix is a non initialized local variable.
String
question 9 10: traversing a string with while
1
2
3
4
5
6
7
8
9
10
void q9(){
char * my_string="<-_->";
printf("%s\n",my_string);
char * pt=my_string;
while(*pt!='\0'){
printf("%c.",*pt);
pt++;
}
printf("\n");
}
1
2
3
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part2
<-_->
<.-._.-.>.
question 11: traversing a string with for
1
2
3
4
5
6
7
void q11(){
char* my_string="<-_->";
for(int i=0;i<strlen(my_string);i++){
printf("%c.",my_string[i]);
}
printf("\n");
}
1
2
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part2
<.-._.-.>.
question 12: conversion from string to int
void q12(){
char myString[50];
scanf("%s",myString);
int i=strtoimax(myString,NULL,10);
printf("%d\n",i%4);
}
question 13: diy strcmp()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
int TP_strcmp(const char* s1,const char* s2)
{
int ret=0;
int i=0;
while(s1[i]!='\0'&&s2[i]!='\0'){
if(s1[i]!=s2[i]){
ret=s1[i]-s2[i];
break;
}
i++;
}
if(!ret){
if(s1[i]!='\0') ret=1;
if(s2[i]!='\0') ret=-1;
}
return ret;
}
int main(int argc,char * argv[]){
printf("%d\n",TP_strcmp("hello","hello"));
printf("%d\n",TP_strcmp("hello world","hello"));
printf("%d\n",TP_strcmp("chris evans","chris pratt"));
return 0;
}
1
2
3
4
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part2
0
1
-11
Pointer/array equivalence
question 14 15:
1
2
3
4
5
6
7
8
9
10
11
12
void q14(){
int tab[5][7];
int* tab_addr=&tab;
int* tab_point=tab;
int* tab_point_elt=&tab[0];
printf("tab_addr: %p\n",tab_addr);
printf("tab_point: %p\n",tab_point);
printf("tab_point_elt: %p\n",tab_point_elt);
printf("tab[2][2] %d\n",tab[2][2]);
printf("tab[1][5] %d\n",tab[1][5]);
printf("*tab_point_elt+12 %d\n",*(tab_point_elt+12));
}
1
2
3
4
5
6
7
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part2
tab_addr: 0x7fffb5bc0e40
tab_point: 0x7fffb5bc0e40
tab_point_elt: 0x7fffb5bc0e40
tab[2][2] 0
tab[1][5] -1245744536
*tab_point_elt+12 -1245744536
&tab
,tab
,&tab[0]
mean the same addressint tab[5][7]
is a array which contains 5 array containing 7 int
Structures
question 16: birthday type
1
2
3
4
5
6
enum mois {Jan,Feb,Mar,Avr,Mai,Jun,Jui,Aou,Sep,Oct,Nov,Dec};
typedef struct{
int year;
enum mois month;
int day;
}birthday;
question 17: student type
1
2
3
4
5
6
typedef struct{
int id;
birthday b;
char boissonPreferee[20];
char nom[20];
}student;
question 18: declaration of structures
1
2
3
4
5
int main(int argc,char * argv[]){
student fetard [3];
printf("%d\n",fetard[0].b.month);
return 0;
}
1
2
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part2
827681440
pointer arithmetics
question 20:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void q20(){
int A[]={12,23,34,45,56,67,78,89,90};
int *P;
P=A;
int i1=*P+2; //14
int i2=*(P+2); //34
int* a1= &A[4]-3; //A[1]
int* a2=A+3; //A[3]
int i3=&A[7]-P; //7
int* a3=P+(*P-10); //A[2]
int i4=*(P+*(P+8)-A[7]);//23
int i=0;
for(i=0;i<9;i++){
printf("A[%d]:%p\n",i,&A[i]);
}
printf("i1:%d\n",i1);
printf("i2:%d\n",i2);
printf("a1:%p\n",a1);
printf("a2:%p\n",a2);
printf("i3:%d\n",i3);
printf("a3:%p\n",a3);
printf("i4:%d\n",i4);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part2
A[0]:0x7ffd882fb400
A[1]:0x7ffd882fb404
A[2]:0x7ffd882fb408
A[3]:0x7ffd882fb40c
A[4]:0x7ffd882fb410
A[5]:0x7ffd882fb414
A[6]:0x7ffd882fb418
A[7]:0x7ffd882fb41c
A[8]:0x7ffd882fb420
i1:14
i2:34
a1:0x7ffd882fb404
a2:0x7ffd882fb40c
i3:7
a3:0x7ffd882fb408
i4:23
question 21: gdb
We can also use a gdb to supervisor the value of variables.
question 22: priority of * and + / & and +
- * has a greater priority than +
- & has a greater priority than +
Parametered main()
int main(int argc, char* argv[])
: the type of argv is a array which contains the pointer of char (string)
question 23: display all parameters
1
2
3
4
5
6
7
int main(int argc,char * argv[]){
int i;
for(i=0;i<argc;i++){
printf("%s\n",argv[i]);
}
return 0;
}
1
2
3
4
5
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part2 arg1 arg2 arg3
./Part2
arg1
arg2
arg3
question 24: argv[0]
argv[0] corresponds to the name of executable
question 25:
1
2
3
4
5
6
7
8
9
10
11
12
13
int main(int argc,char * argv[]){
if(argv[1]){
long int li=strtol(argv[1],NULL,10);
int i;
for(i=0;i<li;i++){
printf("*");
}
printf("\n");
}else{
printf("no number\n");
}
return 0;
}
1
2
3
4
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part2
no number
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part2 5
*****
r-value l-value
lvalue and rvalue
Un objet est un emplacement mémoire identifiable (par exemple une variable locale int locale).
Contre-exemple : le résultat d’une opération arithmétique n’est pas un objet. Une l-value est une expression identifiant un objet ; elle a donc un emplacement mémoire identifiable. Elle peut donc être affectée. Par exemple : locale = 4. Une l-value peut donc être :
— le nom d’une variable (de n’importe quel type)
— un emplacement d’un tableau (via l’opérateur[])
— un déréférencement (via l’opérateur*)
— un accès à un membre d’une structure
— une l-value entre parenthèse
Une r-value est une valeur qui ne persiste pas après son usage dans une expression. Par exemple
la valeur 4. Elle n’a pas d’emplacement mémoire identifiable.
Une l-value peut être utilisée comme une r-value mais l’inverse n’est pas vrai !
question 26:
-
1 2 3 4 5
void q26() { int var=0; 4=var; (var+1)=4; }
1 2 3 4 5 6
Part2.c: In function ‘q26’: Part2.c:159:14: error: lvalue required as left operand of assignment int var=0; 4=var; ^ Part2.c:160:9: error: lvalue required as left operand of assignment (var+1)=4;
-
1 2 3 4 5 6
void q26() { int arr[]={1,2}; int* p=&arr[0]; *(p+1)=10; }
No error.
-
1 2 3 4 5
void q26() { int var=10; int* addr=&(var+1); }
1 2 3
Part2.c: In function ‘q26’: Part2.c:165:12: error: lvalue required as unary ‘&’ operand int* addr=&(var+1);
-
1 2 3 4 5 6 7
void q26() { typedef enum color{red,green,blue} color; color c; c=green; blue=green; }
1 2 3 4
Part2.c: In function ‘q26’: Part2.c:169:6: error: lvalue required as left operand of assignment blue=green; ^
-
1 2 3 4 5
void q26() { int var=0; &var=40; }
1 2 3 4
Part2.c: In function ‘q26’: Part2.c:171:6: error: lvalue required as left operand of assignment &var=40; ^
Function pointer
Two ways to use a function pointer:
- As a variable:
We should specify the parameters and the return type to declare a function pointer.
We can assign to a funtion pointer an address of a function
1
2
3
4
5
6
7
8
int max(int x,int y)
{
return x>y? x:y;
}
int(*p)(int,int);
p=&max;//& can be omitted
int a=1,b=2
int bigger=p(a,b)// same thing as int bigger=max(a,b)
-
As a parameter:
These two signatures work both.
1 2
void foo(int pfunc(int),int* tab,int size); void foo(int (* pfunc)(int),int *tab,int size);
question 27 28 29:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int fois_deux(int a)
{
return 2*a;
}
void appliquer_tableau(int pfunc(int),int* tab,int size)
{
int i;
for(i=0;i<size;i++){
tab[i]=pfunc(tab[i]);
}
}
int main(int argc,char * argv[]){
int arr[]={1,2,3,4,5};
appliquer_tableau(&fois_deux,arr,5);
int i;
for(i=0;i<5;i++){
printf("%d ",arr[i]);
}
printf("\n");
}
1
2
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part2
2 4 6 8 10
question 30:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
int superieur(int a,int b){
if(a>b) return 1;
else if(a<b) return -1;
else return 0;
}
int inferieur(int a,int b){
if(a<b) return 1;
else if(a>b) return -1;
else return 0;
}
void tri(int* t, int n,int(* compare)(int,int))
{
int i, i_max, j, tmp;
for(i=0 ; i < n-1 ; i++) {
i_max=i;
for(j=i; j<n; j++) {
if(compare(t[j],t[i_max])==1) {
i_max=j;
}
}
tmp = t[i_max];
t[i_max] = t[i];
t[i] = tmp;
}
}
int main(int argc,char * argv[]){
int arr[]={3,8,7,5,4};
tri(arr,5,inferieur);
int i;
for(i=0;i<5;i++){
printf("%d ",arr[i]);
}
printf("\n");
}
1
2
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part2
3 4 5 7 8
Part 3
Input, output
Language de bois
question 1: fgets()
1
char *fgets(char *s, int size, FILE *stream);
1 2 3 4 5 fgets() reads in at most one less than size characters from stream and stores them into the buffer pointed to by s. Reading stops after an EOF or a newline. If a newline is read, it is stored into the buffer. A terminating null byte ('\0') is stored after the last character in the buffer.
Threes cases that ends the lecture of fgets()
:
- number of characters reaches the end
- an EOF
- a newline
question 2: lecture of a file
1
int getc(FILE *stream);
1 2 fgetc() reads the next character from stream and returns it as an unsigned char cast to an int, or EOF on end of file or error.
1
FILE *fopen(const char *pathname, const char *mode);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 The fopen() function opens the file whose name is the string pointed to by pathname and associates a stream with it. The argument mode points to a string beginning with one of the follow‐ ing sequences (possibly followed by additional characters, as described below): r Open text file for reading. The stream is positioned at the beginning of the file. r+ Open for reading and writing. The stream is positioned at the beginning of the file. w Truncate file to zero length or create text file for writing. The stream is positioned at the beginning of the file. w+ Open for reading and writing. The file is created if it does not exist, otherwise it is truncated. The stream is positioned at the beginning of the file. a Open for appending (writing at end of file). The file is cre‐ ated if it does not exist. The stream is positioned at the end of the file. a+ Open for reading and appending (writing at end of file). The file is created if it does not exist. The initial file position for reading is at the beginning of the file, but output is always appended to the end of the file.
1
2
3
4
5
6
7
8
9
void q2(){
FILE *stream=fopen("file.txt","r");
char c;
c=getc(stream);
while(c!=EOF){
printf("%c",c);
c=getc(stream);
}
}
1
2
3
4
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part3
This is a demo file.
Here we go.
End.
question 3:
void q3(FILE* newfile){
int i;
for(i=1;i<=4;i++){
char name[80]="colonne";
char index[2];
index[0]=i+'0';//trick
index[1]='\0';//indispensable
strcat(name,index);
strcat(name,".txt");
FILE *colonne=fopen(name,"r");
int nb=rand()%8;
int compteur=0;
char phrase[101];
while(compteur<=nb){
fgets(phrase,100,colonne);
compteur++;
}
fputs(phrase,newfile);
fclose(colonne);
}
}
int main(){
FILE *bois=fopen("bois.txt","w+");
q3(bois);
fclose(bois);
return 0;
}
1
2
3
4
Et ce n'est certainement pas vous, mes chers compatriotes, qui me contredirez si je vous dis que
l'aspiration plus que legitime de chacun au progres social
oblige a la prise en compte encore plus effective
d'une valorisation sans concession de nos caracteres specifiques.
question 4:
1
2
3
4
5
6
7
8
void q4(){
int i;
FILE *discours=fopen("discours.txt","w+");
for(i=0;i<5;i++){
q3(discours);
}
fclose(discours);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Et ce n'est certainement pas vous, mes chers compatriotes, qui me contredirez si je vous dis que
l'aspiration plus que legitime de chacun au progres social
oblige a la prise en compte encore plus effective
d'une valorisation sans concession de nos caracteres specifiques.
Je reste fondamentalement persuade que
la necessite de repondre a votre inquietude journaliere, que vous soyez jeunes ou ages,
interpelle le citoyen que je suis et nous oblige tous a aller de l'avant dans la voie
d'un plan correspondant veritablement aux exigences legitimes de chacun.
Je reste fondamentalement persuade que
le particularisme du a notre histoire unique
interpelle le citoyen que je suis et nous oblige tous a aller de l'avant dans la voie
d'une valorisation sans concession de nos caracteres specifiques.
Des lors, sachez que je me battrai pour faire admettre que
la volonte farouche de sortir notre pays de la crise
a pour consequence obligatoire l'urgente nécessite
d'un programme plus humain, plus fraternel et plus juste.
Je tiens à vous dire ici ma determination sans faille pour clamer haut et fort que
l'acuite des problemes de la vie quotidienne
conforte mon desir incontestable d'aller dans le sens
d'un processus allant vers plus d'egalite.
DIY printf()
In this part we can only use putchar()
to display.
1 2 3 4 5 6 7 8 9 fputc() writes the character c, cast to an unsigned char, to stream. fputs() writes the string s to stream, without its terminating null byte ('\0'). putc() is equivalent to fputc() except that it may be implemented as a macro which evaluates stream more than once. putchar(c) is equivalent to putc(c, stdout).
question 5: unsigned int
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void printf_unsigned_int(unsigned int value){
char buffer[20];
int nb=0;
while(value>0){
buffer[nb++]=value%10+'0';
value/=10;
}
int i;
for(i=nb-1;i>=0;i--){
putchar(buffer[i]);
}
if(!nb){
putchar('0');
}
}
int main(){
printf_unsigned_int(0);
printf("\n");
printf_unsigned_int(UINT_MAX);
printf("\n");
return 0;
}
1
2
3
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part3
0
4294967295
quesiton 6: signed int
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void printf_signed_int(int value){
if(value<0){
putchar('-');
printf_unsigned_int(-1*value);
}else{
printf_unsigned_int(value);
}
}
int main(){
printf_signed_int(INT_MIN);
printf("\n");
printf_signed_int(INT_MAX);
printf("\n");
return 0;
}
1
2
3
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part3
-2147483648
2147483647
question 7: float
void printf_float(float value){
long entier=(long) (value);
if(!entier){
if(value<0){
putchar('-');
}
putchar('0');
}else{
if(entier<0){
entier*=-1;
}
char buffer[20];
int nb=0;
while(entier>0){
buffer[nb++]=entier%10+'0';
entier/=10;
}
int i;
for(i=nb-1;i>=0;i--){
putchar(buffer[i]);
}
if(!nb){
putchar('0');
}
//printf_signed_int(entier);
//precision lost because of int casting
}
putchar('.');
float nonentier=value-(long)value;
if(nonentier<0){
nonentier*=-1;
}
int i;
for(i=0;i<6;i++){
nonentier*=10;
int digit=nonentier;
putchar(digit+'0');
nonentier=nonentier-(int)nonentier;
}
}
int main(){
printf("%f\n",3.56f);
printf_float(3.56);
printf("\n");
printf("%f\n",-0.000123f);
printf_float(-0.000123);
printf("\n");
printf("%f\n",1e16f);
printf_float(1e16);
printf("\n");
return 0;
}
1
2
3
4
5
6
7
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part3
3.560000
3.559999
-0.000123
-0.000123
10000000272564224.000000
10000000272564224.000000
question 9: variadic_function
Sa signature doit comporter au moins un argument nommé (ou plusieurs) et se terminer par des points de suspension, par exemple :
int mafonction(int arg1, int arg2, …)
L’utilisateur peut ensuite invoquer mafonction en utilisant la notation classique :
x = mafonction(36, 15, 3.14, &var, “blabla”);
Remarque
Attention, les arguments anonymes ne subissent pas de contrôle de type au moment de la
compilation ! L’auteur du code a la responsabilité de documenter explicitement la
convention d’appel de sa fonction, par exemple : «tous les paramètres anonymes doivent être des flottants», ou «doivent être des pointeurs», etc. Dans le cas de printf , il y a un unique paramètre obligatoire (de type chaîne de caractères) et la convention d’appel est une correspondance non-triviale entre le contenu de cette chaîne et les arguments optionnels
We must use the mecanism in the stdarg.h
:
va_list
pour déclarer un iterateur
va_start(ap, arg2)
: initialiser
va_arg(ap, type)
va simultanément nous renvoyer la valeur de l’argument courant et faire avancer le curseur jusqu’à l’argument suivant. Attention à bien préciser le bon type à chaque fois, sous peine de recevoir des valeur aberrantes et/ou de faire crasher le programme
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdarg.h>
void print_float_list(int count,...){
va_list ap;//déclaration of the iterator
va_start(ap,count);//initialization of the iterator
int j;
for(j=0;j<count;j++){
printf_float(va_arg(ap,double));// ! here the type is double
putchar('\n');
}
va_end(ap);
}
int main(){
print_float_list(3,3.14f,0.142857f,1.41f);
}
The reason why type is double instead of float:
1
2
3
4
5
Part3.c:99:3: warning: ‘float’ is promoted to ‘double’ when passed through ‘...’
printf_float(va_arg(ap,float));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Part3.c:99:3: note: (so you should pass ‘double’ not ‘float’ to ‘va_arg’)
Part3.c:99:3: note: if this code is reached, the program will abort
1
2
3
4
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part3
3.140000
0.142857
1.409999
If instead of 3, we entered 4 for counter:
1
2
3
4
5
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part3
3.140000
0.142857
1.409999
0.000000
question 10: my own printf()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
void mon_printf(char *string,...){
va_list ap;
int i=0;
char c;
va_start(ap,string);
while((c=string[i++])!='\0'){
if(c!='%'){
putchar(c);
}else{
char marqueur=string[i++];
if(marqueur=='d'){
printf_signed_int(va_arg(ap,int));
}
else if(marqueur=='u'){
printf_unsigned_int(va_arg(ap,unsigned int));
}
else if(marqueur=='f'){
printf_float(va_arg(ap,double));
}
else if(marqueur=='c'){
putchar(va_arg(ap,int));
}
else if(marqueur=='s'){
char* str=va_arg(ap,char*);
int j=0;
while(str[j]!='\0'){
putchar(str[j++]);
}
}
}
}
}
int main(){
mon_printf("texte:%s\nnb entier:%d\nnb a virgule:%f\n","bonjour",12345,3.141593);
}
1
2
3
4
mengxin@mengxin-VirtualBox:~/Documents/Programmation-C$ ./Part3
texte:bonjour
nb entier:12345
nb a virgule:3.141592
References
http://www.cplusplus.com/reference/cstdio/printf/
http://www.cplusplus.com/reference/climits/7
https://www.cs.utah.edu/~regehr/papers/overflow12.pdf