Category:Architecture/Development/C

From aldeid
Jump to navigation Jump to search
You are here:
C

Compilation

Definitions

                                                                              *.so
                                                                              *.dll
                                                                            ┌────────┐
                                                                            │ extern │--┐
                                                                            │  libs  │  |
                                                                            └────────┘  |
┌────────┐               ┌──────────────┐           ┌──────────┐            ┌────────┐  |      ┌────────────┐
│ Source │-------------► │ preprocessed │---------► │ Assembly │----------► │ Object │--┴----► │ Executable │
│  code  │ preprocessor  │     code     │ compiler  │   code   │ assembler  │  code  │ linker  │    code    │
└────────┘               └──────────────┘           └──────────┘            └────────┘         └────────────┘
 code.h                       code.i                   code.s                 code.o                code
 code.c                                                                                           code.exe

Tools

Linux

gcc

To compile an executable (myexecutable) from a C source code (code.c:

$ gcc -o myexecutable code.c

Main options

-g
tells GCC to include debug information into the binary.
-Wall
Warning all : print every warning. This switch is used by the C compiler only.
-Idir dir
Look for included header files (like in #include <myheader.h>) in directory dir. This switch is used by the C preprocessor only.
-llib lib
Link to library lib; here libxml2, used by the linker.

make

To compile an executable from a C source code using the make command, create a makefile file as follows:

makefile
CFLAGS=-Wall -g

clean:
	rm -f code
Warning
Notice that TAB should be used to indent lines under the clean section, instead of SPACE.

Then compile using make as follows:

$ make code
cc -Wall -g    code.c   -o code

Notice that the above makefile template provides a clean method:

$ make clean
rm -f code

Windows

On Windows, I recommend MinGW. Most of the advanced IDEs (e.g. Microsoft Visual Studio) will also embed their own compilers.

Arguments

Source Run
#include <stdio.h>

int main(int argc, char *argv[])
{
    int i;

    printf("Name of executable: %s\n", argv[0]);
    if (argc < 2) {
        printf("No argument\n");
    } else {
        printf("%d argument(s)\n", argc-1);
        for (i=0; i<argc-1; i++) {
            printf("- arg %d: %s\n", i+1, argv[i+1]);
        }
    }
    return 0;
}
$ ./code 
Name of executable: ./code
No argument
$ ./code abc
Name of executable: ./code
1 argument(s)
- arg 1: abc
$ ./code abc 123
Name of executable: ./code
2 argument(s)
- arg 1: abc
- arg 2: 123
Note
Like in many other languages, argv[0] is the name of the executable itself. Hence, our loop begins at the 2nd argument, which is actually the 1st real argument our program is provided with.

C Data Types

Integer types

Type Storage size* Value range*
char 1 byte -128 to 127 or 0 to 255
unsigned char 1 byte 0 to 255
signed char 1 byte -128 to 127
int 2 or 4 bytes -32,768 to 32,767 or -2,147,483,648 to 2,147,483,647
unsigned int 2 or 4 bytes 0 to 65,535 or 0 to 4,294,967,295
short 2 bytes -32,768 to 32,767
unsigned short 2 bytes 0 to 65,535
long 4 bytes -2,147,483,648 to 2,147,483,647
unsigned long 4 bytes 0 to 4,294,967,295

(*) May vary depending on the environment.

Floating-point types

Type Storage size Value range Precision
float 4 byte 1.2E-38 to 3.4E+38 6 decimal places
double 8 byte 2.3E-308 to 1.7E+308 15 decimal places
long double 10 byte 3.4E-4932 to 1.1E+4932 19 decimal places

Working with strings

Initialization

Strings

Source Run
#include <stdio.h>

int main(int argc, char *argv[])
{
    // Common ways to declare/initialize strings
    char welcome[] = "Hello world!"; // automatic sizing
    char yourname[21]; // Size of 20 chars + trailing null 
    char yourcolor[11]; // Size of 10 chars + trailing null
    char *myname = "Sebastien"; // Make read-only string
    // Less common way to initialize string
    char mycolor[] = {'b', 'l', 'u', 'e', '\0'};

    printf("%s\n", welcome);
    printf("What is your name? ");
    scanf("%20s", yourname);
    printf("What is your favorite color? ");
    scanf("%10s", yourcolor);
    
    printf("Hello %s. Your favorite color is %s\n", yourname, yourcolor);

    printf("BTW, my name is %s and my favorite color is %s.\n", myname, mycolor);

    return 0;
}
$ ./code
Hello world!
What is your name? Alice
What is your favorite color? green
Hello Alice. Your favorite color is green
BTW, my name is Sebastien and my favorite color is blue.

Array of strings

Source Run
#include <stdio.h>

int main(int argc, char *argv[])
{
    char *colors[] = {"red", "blue", "green", "white", "black", "yellow"};
    int i;

    printf("Size of array: %ld\n", sizeof(colors));
    printf("Size of 1st item in array: %ld\n", sizeof(colors[0]));

    for (i=0; i<sizeof(colors)/sizeof(colors[0]); i++) {
        printf("- %s\n", colors[i]);
    }

    return 0;
}
Size of array: 48
Size of 1st item in array: 8
- red
- blue
- green
- white
- black
- yellow

String pointer

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

int main(int argc, char *argv[])
{
  char str[] = "hello"; // my string
  char *pStr = str;     // pointer of my string
  int i = 0;

  for (i=0; i<strlen(str); i++) {
    // show each character of my string, both with indexed value and with pointer value
    printf("%c %c\n", str[i], *(pStr+i));
  }

  return 0;
}
h h
e e
l l
l l
o o

Space

What happens in case we provide a string that contains a space?

$ ./code 
What is your name? Albert Farnsworth
Hello Albert
BTW, my name is: Sebastien

A space is saved in memory as 0x00 which is interpreted as a NULL character to terminate the string. Hence, in memory, we have:

(gdb) r
Starting program: /data/tmp/code 

Breakpoint 1, main (argc=0, argv=0x0) at code.c:4
4    {
(gdb) x/20i $pc
=> 0x400556 <main>:    push   rbp
   0x400557 <main+1>:    mov    rbp,rsp
   0x40055a <main+4>:    sub    rsp,0x30
   0x40055e <main+8>:    mov    DWORD PTR [rbp-0x24],edi
   0x400561 <main+11>:    mov    QWORD PTR [rbp-0x30],rsi
   0x400565 <main+15>:    mov    QWORD PTR [rbp-0x8],0x400654
   0x40056d <main+23>:    mov    edi,0x40065e
   0x400572 <main+28>:    mov    eax,0x0
   0x400577 <main+33>:    call   0x400420 <printf@plt>
   0x40057c <main+38>:    lea    rax,[rbp-0x20]
   0x400580 <main+42>:    mov    rsi,rax
   0x400583 <main+45>:    mov    edi,0x400672
   0x400588 <main+50>:    mov    eax,0x0
   0x40058d <main+55>:    call   0x400440 <__isoc99_scanf@plt>
   0x400592 <main+60>:    lea    rax,[rbp-0x20]
   0x400596 <main+64>:    mov    rsi,rax
   0x400599 <main+67>:    mov    edi,0x400677
   0x40059e <main+72>:    mov    eax,0x0
   0x4005a3 <main+77>:    call   0x400420 <printf@plt>
   0x4005a8 <main+82>:    mov    rax,QWORD PTR [rbp-0x8]
(gdb) b *0x400596
Breakpoint 2 at 0x400596: file code.c, line 10.
(gdb) c
Continuing.
What is your name? Albert Farnsworth

Breakpoint 2, 0x0000000000400596 in main (argc=1, argv=0x7fffffffe168) at code.c:10
10      printf("Hello %s\n", myname);
(gdb) x/s $rax
0x7fffffffe060:    "Albert"
(gdb) x/20x $rax
0x7fffffffe060:    0x41    0x6c    0x62    0x65    0x72    0x74    0x00    0x00
0x7fffffffe068:    0x60    0x04    0x40    0x00    0x00    0x00    0x00    0x00
0x7fffffffe070:    0x60    0xe1    0xff    0xff

Char Overflow

What happens in case we provide a string that is longer than the maximum expected length?

$ ./code 
What is your name? My_Name_Is_Too_Long_To_Be_Displayed
Hello My_Name_Is_Too_Long_
BTW, my name is: Sebastien

The name is truncated to 20 characters and a NULL byte is inserted at the 21st character to terminate the string.

(gdb) x/s $rax
0x7fffffffe060:    "My_Name_Is_Too_Long_"
(gdb) x/21x $rax
0x7fffffffe060:    0x4d    0x79    0x5f    0x4e    0x61    0x6d    0x65    0x5f
0x7fffffffe068:    0x49    0x73    0x5f    0x54    0x6f    0x6f    0x5f    0x4c
0x7fffffffe070:    0x6f    0x6e    0x67    0x5f    0x00

Updating string

The strcpy function can be used to update a string, as depicted on the below example:

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

int main(int argc, char *argv[])
{
  char str[] = "hello";
  printf("Initial str: %s\n", str);
  strcpy(str, "world");
  printf("Updated str: %s\n", str);
  return 0;
}
Initial str: hello
Updated str: world

Pointers

Lexicon

Syntax Description Example
Source Output
type *ptr a pointer of type named ptr
#include <stdio.h>

int main(int argc, char *argv[])
{
  char *names[] = {"Etch", "Lenny", "Squeeze", "Wheezy", "Jessie", "Stretch"};
  printf("Testing version is now: %s\n", names[5]);
  return 0;
}
Testing version is now: Stretch
*ptr the value of whatever ptr is pointed at
#include <stdio.h>
int main() 
{
  int a = 15;
  int *b = NULL;
  b = &a;
  printf("Address of a: %p\n", b);
  printf("Value at address of a: %d\n", *b);
  return 0;
}
Address of a: 0xffe447c8
Value at address of a: 15
&thing the address of thing
*(ptr + i) the value of (whatever ptr is pointed at plus i)
#include <stdio.h>

int main(int argc, char *argv[])
{
  int t[3] = {8, 12, 15};
  printf("t is a pointer on the 1st item of my array. Address: %p\n", t);
  printf("The 2nd item of my array is: %d\n", *(t+1));
  return 0;
}
t is a pointer on the 1st item of my array. Address: 0xffcd8ed4
The 2nd item of my array is: 12
type *ptr = &thing a pointer of type named ptr set to the address of thing
#include <stdio.h>

int main(int argc, char *argv[])
{
  float pi = 3.14;
  float *ptrPi = &pi;
  printf("%.2f\n", *ptrPi);
  return 0;
}
3.14
ptr++ increment where ptr points
#include <stdio.h>

int main(int argc, char *argv[])
{
  int table[3] = {8, 12, 15};
  int *pTable = table;

  printf("Pointing to 1st item. Address:      %p\n", pTable);
  printf("Value of item pointed to by pTable: %d\n", *pTable);

  pTable++;

  printf("Now pointing to 2nd item. Address:  %p\n", pTable);
  printf("Value of item pointed to by pTable: %d\n", *pTable);

  return 0;
}
Pointing to 1st item. Address:      0xffa25e50
Value of item pointed to by pTable: 8
Now pointing to 2nd item. Address:  0xffa25e54
Value of item pointed to by pTable: 12

int and char pointers

Source Run
#include <stdio.h>

int main(int argc, char *argv[])
{
    int versions[] = {4, 5, 6, 7, 8, 9};
    char *names[] = {"Etch", "Lenny", "Squeeze", "Wheezy", "Jessie", "Stretch"};

    int *current_version = versions;
    char **current_name = names;

    int count = sizeof(versions) / sizeof(versions[0]);
    int i = 0;

    for (i=0; i<count; i++) {
        printf("Version %d has code name %s (index).\n", versions[i], names[i]);
        printf("Version %d has code name %s (pointer index).\n", current_version[i], current_name[i]);
        printf("Version %d has code name %s (pointer).\n", *(current_version+i), *(current_name+i));
        printf("-----\n");
    }

    return 0;
}
$ ./code 
Version 4 has code name Etch (index).
Version 4 has code name Etch (pointer index).
Version 4 has code name Etch (pointer).
-----
Version 5 has code name Lenny (index).
Version 5 has code name Lenny (pointer index).
Version 5 has code name Lenny (pointer).
-----
Version 6 has code name Squeeze (index).
Version 6 has code name Squeeze (pointer index).
Version 6 has code name Squeeze (pointer).
-----
Version 7 has code name Wheezy (index).
Version 7 has code name Wheezy (pointer index).
Version 7 has code name Wheezy (pointer).
-----
Version 8 has code name Jessie (index).
Version 8 has code name Jessie (pointer index).
Version 8 has code name Jessie (pointer).
-----
Version 9 has code name Stretch (index).
Version 9 has code name Stretch (pointer index).
Version 9 has code name Stretch (pointer).
-----

For reference, below is the 32bit disassembled version:

.text:0804841B ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:0804841B                 public main
.text:0804841B main            proc near
.text:0804841B
.text:0804841B names           = byte ptr -48h
.text:0804841B versions        = byte ptr -30h
.text:0804841B count           = dword ptr -18h
.text:0804841B current_name    = dword ptr -14h
.text:0804841B current_version = dword ptr -10h
.text:0804841B i               = dword ptr -0Ch
.text:0804841B var_4           = dword ptr -4
.text:0804841B argc            = dword ptr  0Ch
.text:0804841B argv            = dword ptr  10h
.text:0804841B envp            = dword ptr  14h
.text:0804841B
.text:0804841B                 lea     ecx, [esp+4]
.text:0804841F                 and     esp, 0FFFFFFF0h
.text:08048422                 push    dword ptr [ecx-4]
.text:08048425                 push    ebp
.text:08048426                 mov     ebp, esp
.text:08048428                 push    ecx
.text:08048429                 sub     esp, 44h
.text:0804842C                 mov     dword ptr [ebp+versions], 4
.text:08048433                 mov     dword ptr [ebp+versions+4], 5
.text:0804843A                 mov     dword ptr [ebp+versions+8], 6
.text:08048441                 mov     dword ptr [ebp+versions+0Ch], 7
.text:08048448                 mov     dword ptr [ebp+versions+10h], 8
.text:0804844F                 mov     dword ptr [ebp+versions+14h], 9
.text:08048456                 mov     dword ptr [ebp+names], offset aEtch ; "Etch"
.text:0804845D                 mov     dword ptr [ebp+names+4], offset aLenny ; "Lenny"
.text:08048464                 mov     dword ptr [ebp+names+8], offset aSqueeze ; "Squeeze"
.text:0804846B                 mov     dword ptr [ebp+names+0Ch], offset aWheezy ; "Wheezy"
.text:08048472                 mov     dword ptr [ebp+names+10h], offset aJessie ; "Jessie"
.text:08048479                 mov     dword ptr [ebp+names+14h], offset aStretch ; "Stretch"
.text:08048480                 lea     eax, [ebp+versions]
.text:08048483                 mov     [ebp+current_version], eax
.text:08048486                 lea     eax, [ebp+names]
.text:08048489                 mov     [ebp+current_name], eax
.text:0804848C                 mov     [ebp+count], 6
.text:08048493                 mov     [ebp+i], 0
.text:0804849A                 mov     [ebp+i], 0
.text:080484A1                 jmp     loc_8048542
.text:080484A6 ; ---------------------------------------------------------------------------
.text:080484A6
.text:080484A6 loc_80484A6:
.text:080484A6                 mov     eax, [ebp+i]
.text:080484A9                 mov     edx, dword ptr [ebp+eax*4+names]
.text:080484AD                 mov     eax, [ebp+i]
.text:080484B0                 mov     eax, dword ptr [ebp+eax*4+versions]
.text:080484B4                 sub     esp, 4
.text:080484B7                 push    edx
.text:080484B8                 push    eax
.text:080484B9                 push    offset format   ; "Version %d has code name %s (index).\n"
.text:080484BE                 call    _printf
.text:080484C3                 add     esp, 10h
.text:080484C6                 mov     eax, [ebp+i]
.text:080484C9                 lea     edx, ds:0[eax*4]
.text:080484D0                 mov     eax, [ebp+current_name]
.text:080484D3                 add     eax, edx
.text:080484D5                 mov     edx, [eax]
.text:080484D7                 mov     eax, [ebp+i]
.text:080484DA                 lea     ecx, ds:0[eax*4]
.text:080484E1                 mov     eax, [ebp+current_version]
.text:080484E4                 add     eax, ecx
.text:080484E6                 mov     eax, [eax]
.text:080484E8                 sub     esp, 4
.text:080484EB                 push    edx
.text:080484EC                 push    eax
.text:080484ED                 push    offset aVersionDHasC_0 ; "Version %d has code name %s (pointer in"...
.text:080484F2                 call    _printf
.text:080484F7                 add     esp, 10h
.text:080484FA                 mov     eax, [ebp+i]
.text:080484FD                 lea     edx, ds:0[eax*4]
.text:08048504                 mov     eax, [ebp+current_name]
.text:08048507                 add     eax, edx
.text:08048509                 mov     edx, [eax]
.text:0804850B                 mov     eax, [ebp+i]
.text:0804850E                 lea     ecx, ds:0[eax*4]
.text:08048515                 mov     eax, [ebp+current_version]
.text:08048518                 add     eax, ecx
.text:0804851A                 mov     eax, [eax]
.text:0804851C                 sub     esp, 4
.text:0804851F                 push    edx
.text:08048520                 push    eax
.text:08048521                 push    offset aVersionDHasC_1 ; "Version %d has code name %s (pointer).\"...
.text:08048526                 call    _printf
.text:0804852B                 add     esp, 10h
.text:0804852E                 sub     esp, 0Ch
.text:08048531                 push    offset s        ; "-----"
.text:08048536                 call    _puts
.text:0804853B                 add     esp, 10h
.text:0804853E                 add     [ebp+i], 1
.text:08048542
.text:08048542 loc_8048542:
.text:08048542                 mov     eax, [ebp+i]
.text:08048545                 cmp     eax, [ebp+count]
.text:08048548                 jl      loc_80484A6
.text:0804854E                 mov     eax, 0
.text:08048553                 mov     ecx, [ebp+var_4]
.text:08048556                 leave
.text:08048557                 lea     esp, [ecx-4]
.text:0804855A                 retn
.text:0804855A main            endp

Send pointer to function

Source Run
#include <stdio.h>

void triple(int *pNum);

int main(int argc, char *argv[])
{
  int num = 5;
  printf("Num before function: %d\n", num);
  // Send address of num to function
  triple(&num);
  printf("Num after function: %d\n", num);
  return 0;
}

void triple(int *pNum)
{
  // Multiply by 3 value pointed by pointer
  *pNum *= 3;
}
$ ./code
Num before function: 5
Num after function: 15

Below is the disassembled code:

.text:080483EB ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:080483EB                 public main
.text:080483EB main            proc near
.text:080483EB
.text:080483EB num             = dword ptr -0Ch
.text:080483EB var_4           = dword ptr -4
.text:080483EB argc            = dword ptr  0Ch
.text:080483EB argv            = dword ptr  10h
.text:080483EB envp            = dword ptr  14h
.text:080483EB
.text:080483EB                 lea     ecx, [esp+4]
.text:080483EF                 and     esp, 0FFFFFFF0h
.text:080483F2                 push    dword ptr [ecx-4]
.text:080483F5                 push    ebp
.text:080483F6                 mov     ebp, esp
.text:080483F8                 push    ecx
.text:080483F9                 sub     esp, 14h
.text:080483FC                 mov     [ebp+num], 5
.text:08048403                 mov     eax, [ebp+num]
.text:08048406                 sub     esp, 8
.text:08048409                 push    eax             ; eax = 5 (initial value)
.text:0804840A                 push    offset format   ; "Num before function: %d\n"
.text:0804840F                 call    _printf         ; print 5 (initial value)
.text:08048414                 add     esp, 10h
.text:08048417                 sub     esp, 0Ch
.text:0804841A                 lea     eax, [ebp+num]  ; Address of num sent to function
.text:0804841D                 push    eax
.text:0804841E                 call    triple
.text:08048423                 add     esp, 10h
.text:08048426                 mov     eax, [ebp+num]  ; eax = Initial value multiplied by 3 by function
.text:08048429                 sub     esp, 8
.text:0804842C                 push    eax             ; eax = 5*3 = 15
.text:0804842D                 push    offset aNumAfterFuncti ; "Num after function: %d\n"
.text:08048432                 call    _printf
.text:08048437                 add     esp, 10h
.text:0804843A                 mov     eax, 0
.text:0804843F                 mov     ecx, [ebp+var_4]
.text:08048442                 leave
.text:08048443                 lea     esp, [ecx-4]
.text:08048446                 retn
.text:08048446 main            endp
.text:08048447 ; ==========================================================================================
.text:08048447                 public triple
.text:08048447 triple          proc near
.text:08048447
.text:08048447 pNum            = dword ptr  8
.text:08048447
.text:08048447                 push    ebp
.text:08048448                 mov     ebp, esp
.text:0804844A                 mov     eax, [ebp+pNum]
.text:0804844D                 mov     edx, [eax]      ; edx = Value at address provided as arg to function
.text:0804844F                 mov     eax, edx
.text:08048451                 add     eax, eax        ; \
.text:08048453                 add     edx, eax        ; / edx = Value multiplied by 3
.text:08048455                 mov     eax, [ebp+pNum]
.text:08048458                 mov     [eax], edx      ; Value multiplied by 3 put at address of pointer
.text:0804845A                 nop
.text:0804845B                 pop     ebp
.text:0804845C                 retn
.text:0804845C triple          endp

Note that for char, it's a bit different:

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

void update(int *i, char str[]);

int main(int argc, char *argv[])
{
  int i = 15;
  char str[] = "hello";

  printf("Initial values: %d %s\n", i, str);
  update(&i, str);
  printf("Updated values: %d %s\n", i, str);

  return 0;
}

void update(int *i, char str[])
{
  *i = 30;
  strcpy(str, "world");
}
Initial values: 15 hello
Updated values: 30 world

Function pointer

The following function is just returning the string that it receives as argument.

#include <stdio.h>

char *showstr(char str[]);

int main(int argc, char *argv[])
{
  char str[] = "hello";
  printf("%s", showstr(str));

  return 0;
}

char *showstr(char str[])
{
  return str;
}

Structures

Array of structure

Source Output
main.h
typedef struct Player Player;
struct Player {
  char firstname[20];
  char lastname[20];
};
code.c
#include <stdio.h>
#include "main.h"
#define NPLAYERS 2

int main(int argc, char *argv[])
{
  Player players[NPLAYERS];
  int i=0;

  for (i=0; i<NPLAYERS; i++) {
    printf("=== PLAYER %d ===\n", i+1);
    printf("First name? ");
    scanf("%20s", players[i].firstname);
    printf("Last name? ");
    scanf("%20s", players[i].lastname);
  }

  printf("\n=== PLAYERS ===\n");
  for(i=0; i<NPLAYERS; i++) {
    printf("Player %d: %s %s\n", i+1, players[i].firstname, players[i].lastname);
  }

  return 0;
}
=== PLAYER 1 ===
First name? Alice 
Last name? Shaw
=== PLAYER 2 ===
First name? Foo 
Last name? Bar

=== PLAYERS ===
Player 1: Alice Shaw
Player 2: Foo Bar

Passing structure as function arg

Source Output
main.h
typedef struct Player Player;
struct Player {
  char firstname[20];
  char lastname[20];
  int age;
};

void initPlayer(Player *player);
code.c
#include <stdio.h>
#include <string.h>
#include "main.h"

int main(int argc, char *argv[])
{
  Player player;

  initPlayer(&player);
  printf("Player: %s %s, %d years old\n", player.firstname, player.lastname, player.age);
  return 0;
}

void initPlayer(Player *player)
{
  // Use strcpy when dealing with char
  // First possibility: '->' shortcut
  strcpy(player->firstname, "Alice");
  // Second possibility pointer
  strcpy((*player).lastname, "Shaw");
  // When dealing with int, you can just do as follows
  player->age = 32;
}
Player: Alice Shaw, 32 years old

Memory allocation

Dynamic vs manual memory allocation

The following example shows 2 ways of processing information in memory. The 1st one (Paul's age) uses an automatic/dynamic memory allocation whereas the 2nd one (Alice's age) is manual.

Source Run
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
  // Dynamic mem allocation
  int agePaul = 0;

  // Manual mem allocation
  int *ageAlice = NULL;
  ageAlice = malloc(sizeof(int));
  if(ageAlice==NULL) exit(1);

  printf("How old is Paul? ");
  scanf("%d", &agePaul);

  printf("How old is Alice? ");
  scanf("%d", ageAlice);

  printf("Paul is %d years old and Alice is %d years old.\n", agePaul, *ageAlice);

  free(ageAlice);

  return 0;
}
$ ./code
How old is Paul? 33
How old is Alice? 35
Paul is 33 years old and Alice is 35 years old.

Manual allocation of array

Soiurce Run
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
  int numKids = 0;
  int *ageKids = NULL;
  int i = 0;

  printf("How many kids do you have? ");
  scanf("%d", &numKids);
  ageKids = malloc(numKids * sizeof(int));
  if (ageKids==NULL) exit(1);

  for (i=0; i<numKids; i++) {
    printf("How old is your kid %d? ", i+1);
    scanf("%d", &ageKids[i]);
  }

  printf("\nYour kids are ");
  for (i=0; i<numKids; i++) {
    printf("%d ", ageKids[i]);
  }
  printf("years old.\n");

  free(ageKids);

  return 0;
}
$ ./code 
How many kids do you have? 3
How old is your kid 1? 5
How old is your kid 2? 7
How old is your kid 3? 10

Your kids are 5 7 10 years old.

Some programs

Hangman
The infamous hangman program
Download
Clock ASCII Art
A clock in ASCII art, displayed in the terminal
Download

Subcategories

This category has the following 3 subcategories, out of 3 total.