Tutorials/C Programming Tutorial
C and C++ are cool programming languages, but some things are hard to learn or remember. This page is to make learning this language easier to you. The compiling examples are based on Linux.
Contents |
Introduction
First program
Here is a "hello world" C/C++ program:
main.cpp
#include <iostream> int main() { std::cout << "hello world" << std::endl; }
Build and run it:
g++ -o hello main.cpp && ./hello
Explanation
std::cout is the command to write something "on your screen" (to be more exact, to stdout). std:: is put in front because it is the namespace standard. If you use the command using namespace std; you can omit this. g++ is the gnu c++ compiler. -o hello means it outputs the file "hello".
Hello, Thorsten
We are now going to write a program that asks for your name and says "hello, Thorsten" (in case your name is Thorsten). For that, we need a variable to hold the name that the user inputs:
#include <iostream> using namespace std; int main() { string name; cout << "What is your name? "; cin >> name; cout << "Hello, " << name << endl; }
Explanation
string name tells the program that name is a variable to hold a string (not e.g. a number). cin >> name tells the program you want character input (the opposite direction of charater output, we know the command cout. You input your name and it gets stored in the variable name. Then, "Hello" and the variable's content is output.
C, a functional language
C is a functional language, every command delivers a return value:
std::cout << "the return value of outputting hello world is " << std::cout<< "hello world";
writes something like
the return value of outputting hello world is 0x601068hello world
The compiler does its job till every command is resolved, that means, every command has delivered a return code. That is why you can write return codes into your program without getting error messages:
#include <iostream> using namespace std; int main() { cout << "the return value of outputting hello world is " << cout << "hello world" << endl; 1807; 4711; }
Explanation
cout << "hello world" << endl; delivers a return value although this is void (in the sense of useless). Typically, a return value could be used to indicate whether the command was successful. This return value can be output using another cout command. Every command (so, all what is written before the ;) is evaluated till it finally is a number. This is why a number does not do anything - it is already evaluated till the end. 1807; does nothing.
Building
Building your c program is more complicated than writing it. Here is an example:
main.cpp
#include <stdio.h> int main(int argc, char* argv[]) { printf("hello world"); }
To compile it, you may use g++ or gcc with the respective library:
tweedleburg:~/test # g++ main.cpp tweedleburg:~/test # gcc main.cpp /tmp/ccGoITbg.o:(.eh_frame+0x12): undefined reference to `__gxx_personality_v0' collect2: ld returned 1 exit status tweedleburg:~/test # gcc -lstdc++ main.cpp tweedleburg:~/test #
gcc needs this library because it determines from the suffix it is a C++ program. Tell gcc that it is a C program and it will not need this library:
tweedleburg:~/test # gcc -xc main.cpp tweedleburg:~/test #
or copy main.cpp to main.c and use gcc:
tweedleburg:~/test # gcc main.c tweedleburg:~/test #
library order
The compiler searches for includes first in /usr/local/include then in /usr/include. includes are expected to be named .h or .hpp.
dynamic linking vs static linking
See http://www.linuxintro.org/wiki/Linking.
printf parameters
An integer number divided using the "/" operator by an integer number delivers an integer number, example:
main.cpp
#include <stdio.h> int main() { printf( "%i", 31 / 60); }
Compile, link and run it
g++ main.cpp && ./a.out 0
float
Stupid C only reserves 4 bytes for the result of 31/60, because it thinks 31/60 is an int, 0. So the following yields a random number:
main.cpp
#include <stdio.h> int main() { printf( "%f", 31 / 60); }
To correct this, you have two possibilities:
- write one or two numbers as a floats themselves, e.g.: 31.0/60.0
- cast 31/60 to a float. We will learn casts next.
file operations
main.c
#include <stdio.h> int main() { FILE *handle; handle=fopen("testfile", "wb"); char x[1]; fwrite(x,1,1,handle); }
To build this, do
g++ main.c -o runthis
casts
You can cast the result of 31/60 to be a float like this:
#include <stdio.h> int main() { printf( "%f", (float)31 / 60); }
What does it mean
Imagine you have to analyze C or C++ source code and you come across this sign, say "*" or "&" or "++". There are several meanings of each of it. Fear not! Come here and find them all.
++
There is a ++ operator I always have to look up:
#include <iostream> int main() { int i=5,n=5; std::cout << "i=5;i++:" << i++ << std::endl; std::cout << "n=5;++n:" << ++n << std::endl; }
delivers
i=5;i++:5 n=5;++n:6
- Remember
- i++ delivers i and afterwards increases it. ++i first increases i, then delivers i.
*
A * can mean
- a declaration of a pointer:
int* i;
- a dereferenciation
cout << "i has the value " << *i << endl;
void
- a void pointer is a pointer of an unknown type
- a void function is a function that does not return anything
&
A & can mean
- a bit-wise AND
- a dereferenciation:
int i=5; cout << "memory byte number 5 is " << &i << endl;
- assigning a reference:
#include <iostream> int main() { int donald=1; int &phantomias=donald; // now donald and phantomias mean the same memory address std::cout << "Donald is at address " << &donald << " Phantomias at " << &phantomias << std::endl; // they have the same value std::cout << "Donald has the value " << donald << " Phantomias has " << phantomias << std::endl; phantomias=5; // now donald == 5 std::cout << "Donald has the value " << donald << " Phantomias has " << phantomias << std::endl; }
- declaring call-by-reference
// Copyright (c) by Scott Wheeler, see http://developer.kde.org/~wheeler/cpp-pitfalls.html#references void foo( int &i ) { i++; } int main() { int bar = 5; // bar == 5 foo( bar ); // bar == 6 foo( bar ); // bar == 7 return 0; }
Pointers
A pointer is if you do not store a value in a variable, but the address in memory where the value is stored. In other words, we point to the memory address where the value is stored. The C compiler has the asterix (*) as signal that a pointer starts:
delete 0;
gives you the error message
error: type ‘int’ argument given to ‘delete’, expected pointer
While
delete (int*) 0;
and
delete (void*) 0;
are legal.
Let's write a short program to demonstrate a pointer is different from its value:
main.cpp:
#include <iostream> using namespace std; int foo(int* i) { cout << "You handed over " << *i << endl; cout << "We are talking about the memory address " << i << endl; } int main() { int n=5; foo(&n); int *m=new int(23); foo(m); }
Compile and run it like this:
tweedleburg:~ # g++ main.cpp -o cprogram && ./cprogram You handed over 5 We are talking about the memory address 0x7fffcab8a914 You handed over 23 We are talking about the memory address 0x602010
Now, what happens in this program ?
int *i is a pointer to an int.
cout << i << endl;
shows the address in mem.
cout << *i << endl;
shows the value.
& is the referencing operator, it gives you the memory address of, say, an int. So, if your function foo requires a pointer int* (like *m in this case), you can as well use a referenced int (&n in this case).
You also see that the "new int" is in a different memory segment (the heap, memory address 0x602010) than int n (which is on the stack, memory address 0x7fffcab8a914).
Pointer arithmetics
i++ increases the pointer, so goes to the next int in mem. *i++ is the same as *(i++), so it also increases the pointer. (*i)++ increases the value in the mem by 1.
Pointer naming
char *ch
is a pointer to a char, equivalent to
char* ch
ch can consist of several characters, from the first character at the pointer till the first zero character.
Pointers in memory
You can not do the following code:
char *ch; *ch="hallo";
because at the second line, the pointer does not exist, as C does not know where the free memory is. You must discover and allocate the free memory with malloc first:
char *ch; ch=(char*)malloc(255);
for your convenience, you can also do an implicit malloc if the string length is known when creating the variable:
char *ch="hallo";
Variables that are known at compile time are laid onto the stack. Think of a counter as an example. Variables that are set up during run time (think of books in bookstores: you do not know how many you need before runtime) lodge in the heap. You cannot increase the size of variables on the stack during runtime, but you can for variables in the heap. You get e.g. a variable on the stack with the command
int i;
Use malloc or new to get a "run-time variable", a variable on the heap. Remember to free the memory in the heap again, else, we speak of a memory leak.
Know that a pointer is always as big as you need to identify one atomic part (byte) in the memory. So, under ia32, a pointer is 32bit big, under ia64, it is 64 bit big. And under C, an int is always as big as a pointer under every architecture. So, you can calculate with pointers as with ints. So, under ia32-C, an int is 32 bit big, under ia64, an int is 64 bit big.
Read from a memory address
To read from a memory address, create a pointer and assign it a memory address as in the following example.
main.cpp
#include <iostream> #include <sys/mman.h> using namespace std; int main() { cout << "Pointer manipulation" << endl; int* i; cout << "i is at " << i << " value " << *i << endl; i=(int*)0x400890; cout << "i is at " << i << " value " << *i << endl; // We now try to read from memory address 0x400891 i=(int*)0x400891; cout << "i is at " << i << " value " << *i << endl; }
Compile, link and run
g++ main.cpp && ./a.out
Here are some equivalents:
#include <iostream> #include <sys/mman.h> using namespace std; int main() { cout << "Pointer manipulation" << endl; int* i; cout << "i is at " << i << " value " << (int) *i << endl; // We now try to read from memory address 0x400891 i=(int*)0x400891; cout << "i is at " << i << " value " << (int) *i << endl; // The following is equivalent, but represented in another way int n=0x400891; cout << "n is at " << n << " value " << &n << endl; // The following is equivalent, but represented in another way printf("n is at %i value %i", n, &n); }
Function pointers
main.cpp
#include <iostream> using namespace std; void printhello() { cout << "hello" << endl; } int main() { cout << "printhello is at memory address " << (int*)printhello << endl; }
Compile, link and run
g++ main.cpp && ./a.out
Output
printhello is at memory address 0x4008dc
Calling function pointers
main.cpp
#include <iostream> using namespace std; void printhello() { cout << "hello" << endl; } int main() { cout << "printhello is at memory address " << (int*)printhello << endl; cout << "calling printhello" << endl; ((void(*)()) printhello)(); }
Compile, link and run it using
g++ -o func main.cpp && ./func
In this example,
cout << ((void(*)) printhello) << endl;
outputs a memory address like 0x4008dc
cout << ((void(*)()) printhello) << endl;
outputs a "1".
((void(*)()) 0x4008dc)();
executes the code at 0x4008dc
((void(*)()) 0x4008dc);
does the same (nothing) as if you wrote the code line
1
Memory leaks
Here is how to provoke a memory leak, my program ram_gourmet:
main.cpp
class t { public: t(){}; }; void pollute() { t* polluter=new t(); } int main() { while (true) pollute(); }
Attention: It rendered my compi useless within 10 seconds.
Compile, link and run this using:
g++ -o ram_gourmet main.cpp && ./ram_gourmet
This program can be developed further to be a cache condenser
Assembler
Want to use assembler code in your C program ? Do it like this:
asm.cpp
int main() { asm("nop"); }
Compile this using
g++ asm.cpp
Next interesting thing:
ls3523:~/test # cat main.cpp int main() { int i=5; } ls3523:~/test # g++ -c main.cpp ls3523:~/test # objdump -d main.o main.o: file format elf32-i386 Disassembly of section .text: 00000000 <main>: 0: 8d 4c 24 04 lea 0x4(%esp),%ecx 4: 83 e4 f0 and $0xfffffff0,%esp 7: ff 71 fc pushl 0xfffffffc(%ecx) a: 55 push %ebp b: 89 e5 mov %esp,%ebp d: 51 push %ecx e: 83 ec 10 sub $0x10,%esp 11: c7 45 f8 05 00 00 00 movl $0x5,0xfffffff8(%ebp) 18: b8 00 00 00 00 mov $0x0,%eax 1d: 83 c4 10 add $0x10,%esp 20: 59 pop %ecx 21: 5d pop %ebp 22: 8d 61 fc lea 0xfffffffc(%ecx),%esp 25: c3 ret ls3523:~/test #
ls3166:~ # hwinfo --cpu 01: None 00.0: 10103 CPU [Created at cpu.421] Unique ID: rdCR.j8NaKXDZtZ6 Hardware Class: cpu Arch: IA-64 Vendor: "GenuineIntel" Model: 0.0.5 "Itanium 2" Features: branchlong Clock: 1495 MHz Config Status: cfg=new, avail=yes, need=no, active=unknown 02: None 01.0: 10103 CPU [Created at cpu.421] Unique ID: wkFv.j8NaKXDZtZ6 Hardware Class: cpu Arch: IA-64 Vendor: "GenuineIntel" Model: 0.0.5 "Itanium 2" Features: branchlong Clock: 1495 MHz Config Status: cfg=new, avail=yes, need=no, active=unknown ls3166:~ # cat main.cpp int main() { int i=5; } ls3166:~ # g++ -c main.cpp ls3166:~ # objdump -d main.o main.o: file format elf64-ia64-little Disassembly of section .text: 0000000000000000 <main>: 0: 02 10 00 18 00 21 [MII] mov r2=r12 6: e0 28 00 00 48 00 mov r14=5;; c: 00 00 04 00 nop.i 0x0 10: 02 00 38 04 90 11 [MII] st4 [r2]=r14 16: e0 00 00 00 42 00 mov r14=r0;; 1c: 01 70 00 84 mov r8=r14 20: 11 60 00 04 00 21 [MIB] mov r12=r2 26: 00 00 00 02 00 80 nop.i 0x0 2c: 08 00 84 00 br.ret.sptk.many b0;; ls3166:~ #
UniCode
See Unicode.
Factories
Factories are here to instantiate an object whose type you do not know at compile time - is this right?
Interesting problems
Problem 1
See http://websvn.kde.org/trunk/playground/utils/krep/
this works:
// move the cursor to where it was QTextCursor* t=&mkrep->ktextedit_2->textCursor(); t->setPosition(cursorpos);
but the following not:
mkrep->ktextedit_2->textCursor().setPosition(cursorpos);
Problem 2
If you do not return a value, the program crashes:
testcase.pro
#------------------------------------------------- # # Project created by QtCreator 2010-01-22T11:08:42 # #------------------------------------------------- TARGET = testcase TEMPLATE = app SOURCES += main.cpp\ mainwindow.cpp HEADERS += mainwindow.h FORMS += mainwindow.ui
main.cpp
#include <QtGui/QApplication> #include "mainwindow.h" int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); }
mainwindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = 0); ~MainWindow(); QString crash() {}; // crashes because it returns nothing protected: void changeEvent(QEvent *e); private: Ui::MainWindow *ui; }; #endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); QString qs; qs=crash(); } MainWindow::~MainWindow() { delete ui; } void MainWindow::changeEvent(QEvent *e) { QMainWindow::changeEvent(e); switch (e->type()) { case QEvent::LanguageChange: ui->retranslateUi(this); break; default: break; } }
mainwindow.ui
<ui version="4.0"> <class>MainWindow</class> <widget class="QMainWindow" name="MainWindow" > <property name="geometry" > <rect> <x>0</x> <y>0</y> <width>600</width> <height>400</height> </rect> </property> <property name="windowTitle" > <string>MainWindow</string> </property> <widget class="QMenuBar" name="menuBar" /> <widget class="QToolBar" name="mainToolBar" /> <widget class="QWidget" name="centralWidget" /> <widget class="QStatusBar" name="statusBar" /> </widget> <layoutDefault spacing="6" margin="11" /> <pixmapfunction></pixmapfunction> <resources/> <connections/> </ui>
This also crashes if crash() is defined in the .cpp file. This also crashes if you write crash() instead of qs=crash(). This does not crash if you exchange QString crash() by int crash().
Your programs
- How to simulate a keypress
- How to find out which window has the focus
- How to find out desktop idle time
- How to compile Qt4 programs
- How to use a QTreeWidget
- How to use a QLayOut
- Alliknow.c
- Cpucount.c
- Aliases.cpp
- Syscall.cpp
- Syscall_open_o_direct.cpp
Suggested Readings
- deducting printf
- Thinking in C++ by Bruce Eckels
- C++ pitfalls by Scott Wheeler
- C++ pitfalls (not only) for KDE programming
- http://en.wikibooks.org/wiki/C_Programming