Learning C by Example (2015)
Learning C by Example (2015)
Learning C by Example
Agus Kurniawan
1st Edition, 2015
Copyright 2015 Agus Kurniawan
Table of Contents
Copyright
Preface
1. Development Environment
1.1 Getting Started
1.2 Compilers
1.2.1 Linux
1.2.2 Windows
1.2.3 Mac
1.3 Development Tools
1.4 Hello World
2. Basic C Programming Language
2.1 Common Rule
2.2 Declaring Variable
2.3 Assigning Variables
2.4 Comment
2.5 Input & Output on Console
2.6 Arithmetic Operations
2.7 Mathematical Functions
2.8 Comparison Operators
2.9 Logical Operators
2.10 Increment and Decrement
2.11 Decision
2.11.1 if..then
2.11.2 switch..case
2.12 Iterations
2.12.1 For
2.12.2 While
2.13 Struct
3. Array and Pointer
3.1 Array
3.1.1 Defining An Array
3.1.2 Basic Array Operations
3.2 Multidimensional Array
3.3 Pointer
3.3.1 Basic Pointer
3.3.2 Dynamic Array
4. Functions
4.1 Creating Function
4.2 Function with Parameters and Returning Value
4.3 Function with Array Parameters
4.4 Function and Pointer
5. I/O Operations
5.1 Getting Started
5.2 Reading Input from Keyboard
5.2.1 getchar() and putchar() functions
5.2.2 gets() and puts() functions
5.2.3 scanf() function
5.3 Reading Program Arguments
5.4 Writing Data Into A File
5.5 Reading Data From A File
6. String Operations
6.1 Concatenating Strings
6.2 String To Numeric
6.3 Numeric to String
6.4 String Parser
6.5 Check String Data Length
6.6 Copy Data
6.7 Exploring Characters
7. Building C Library
7.1 Getting Started
10.3.1 Server
10.3.2 Client
10.3.3 Testing
Contact and Source Code
Contact
Preface
This book is a practical book to get started with C language. It describes all the elements
of the language and illustrates their use with code examples.
Agus Kurniawan
Depok, March 2015
1. Development Environment
1.2 Compilers
There are many C compilers to develop C program. In this book, we use GCC as C
compiler for Linux, Mac and Windows. For Windows users, you also can use Visual C++
compiler.
1.2.1 Linux
Installation of GCC C is easy. For Ubuntu Linux, you can do it using console and write
this script
$ sudo apt-get install build-essential
If installation already finished, you can check GCC version on console and write script as
below
gcc --version
You will see gcc version, for instance shown in Figure above.
1.2.2 Windows
If your computer has Windows platform, you can use Cygwin. Download it on
http://cygwin.com/setup.exe and then run it.
On setup dialog, you choose Devel package as follows.
1.2.3 Mac
To install GCC, you can install Xcode so you get GCC. After installed, you can verify it
by checking GCC version.
If you check, you will get file a.out. GCC will generate a.out file if you dont specify an
output file name. You can define the output compiled file as follows
sudo gcc hello.c -o hello
After compiled, you can run the compiled file by writing this command (for instance, the
compiled file is hello.out)
./hello
Once declared, these variables can be used to store data based on its data type.
You must assign a value on a variable properly based on data type. If not, you will get
error on compiling process, for instance, write this code
#include <stdio.h>
int main() {
int n;
int i,j;
n="hello";
return 0;
}
2.4 Comment
You may explain how to work on your code with writing C. To do it, you can use // and /*
*/ syntax. Here is sample code:
// bank account
char accountCode;
/* parameters*/
int p1, p2, p3, p4;
You can see on %f that wrote floating data with 6 decimal digits. You can specify the
number of decimal digit by passing numeric after dot (.), for instance, %.2f and %.3f.
Save this program into a file, called arith.c. Compile and run it.
Program run:
Save this code into a file, called mathdemo.c. Then compile and run it. Because we use
math.h, we add -lm parameter on compiling.
To illustrate how to use logical operators in C code, you can write this code.
#include <stdio.h>
int main() {
int a,b;
a = 5;
b = 8;
printf("%d \n",a>b && a!=b);
printf("%d \n",!(a>=b));
printf("%d \n",a==b || a>b);
return 0;
}
Save this code into a file, logical.c. Compile and run it.
2.11 Decision
There are two approaches to build decision on C. We can use if..then and switch..case.
2.11.1 if..then
Syntax model for if..then can be formulated as below:
if (conditional) {
// do something
}else{
// do another job
}
Save this program into a file, called ifdemo.c. Then, run this file.
Program run:
2.11.2 switch..case
switch..case can be declared as below:
switch(option){
case option1:
// do option1 job
break;
case option2:
// do option2 job
break;
}
Save this code into a file, called switch.c. Try to build and run it.
Program run:
2.12 Iterations
Iteration operation is useful when we do repetitive activities. We use for and while syntax
2.12.1 For
The simple scenario that illustrates iteration scenario is to show list of number. We do
iteration until the number value less than 10.
#include <stdio.h>
int main() {
int i;
for(i=0;i<10;i++){
printf("data %d\n",i);
}
return 0;
}
Save this code into a file, called for.c. Compile and run it.
Here is a program output:
2.12.2 While
The following is the same code like 2.12.1 scenario but it uses while syntax.
#include <stdio.h>
int main() {
int num = 0;
while(num<10){
printf("data %d\n",num);
num++;
}
return 0;
}
Save this code into a file, called while.c. Try to compile and run it.
2.13 Struct
We can define a struct to declare a new data type. We use struct keyword. For illustration,
we define new data type, called employee.
Create a file, called structdemo.c, and write this code.
#include <stdio.h>
// define a struct
struct employee{
int id;
char name[10];
char country[5];
};
int main() {
// declare struct variable
struct employee emp;
// set values
emp.id = 10;
sprintf(emp.name,"jane");
sprintf(emp.country,"DE");
// display
printf("id: %d, name: %s, country: %s\n",emp.id,emp.name,emp.country);
return 0;
}
3.1 Array
In this section, we build an array using C. For illustration, we develop single and multi
dimensional array.
for(i=0;i<5;i++){
numbers[i] = i;
list[i].id = i;
sprintf(list[i].name,"usr %d",i);
sprintf(list[i].country,"DE");
}
sprintf(chars,"hello c");
// display data
for(i=0;i<5;i++){
printf("%d %c\n",numbers[i],chars[i]);
printf("struct. id: %d, name: %s, country: %s \n",
list[i].id,list[i].name,list[i].country);
}
printf("%s\n",chars);
return 0;
}
3.3 Pointer
A pointer is a programming language object, whose value refers to (or points to) another
value stored elsewhere in the computer memory using its address. A pointer references a
location in memory, and obtaining the value stored at that location is known as
dereferencing the pointer (source:
http://en.wikipedia.org/wiki/Pointer_(computer_programming) ).
To obtain memory address of a variable, we can use & syntax. For instance, create a file,
called address.c, and write this code.
#include <stdio.h>
int main(int argc, const char* argv[]) {
int n;
n = 10;
printf("value n: %d \n",n);
printf("address n: %x \n",&n);
return 0;
}
n = 10;
nPtr = &n;
printf("value n: %d \n",n);
printf("address n: %x \n",(unsigned int)&n);
printf("value nPtr: %x \n",(unsigned int)nPtr);
printf("address nPtr: %x \n",(unsigned int)&nPtr);
printf("value pointer nPtr: %d \n",*nPtr);
return 0;
}
You can see a value of nPtr is memory address of variable n. If n is set value 10, then
value of pointer nPtr which we declare as *nPtr is the same value with value of variable n.
A sample of program output is shown in Figure below.
// allocate memory
numbers = malloc( N * sizeof(int));
// set values
int i;
for(i=0;i<N;i++){
numbers[i] = i+3;
}
// display values
for(i=0;i<N;i++){
printf("%d ",numbers[i]);
}
printf("\n");
// free memory
free(numbers);
return 0;
}
Another sample, we also define dynamic array with multidimensional. For instance, we
create two dimensional dynamic array. Create a file, called dtwopointer.c, and write this
code.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, const char* argv[]) {
// define dynamic array of pointer
int **matrix; // two dimensional array pointer
// a number of array
int M = 3;
int N = 5;
// allocate memory
matrix = malloc( M * sizeof(int*));
// set values
int i,j;
for(i=0;i<M;i++){
matrix[i] = malloc( N * sizeof(int));
for(j=0;j<N;j++){
matrix[i][j] = i + j;
}
}
// display values
for(i=0;i<M;i++){
for(j=0;j<N;j++){
printf("%d ",matrix[i][j]);
}
printf("\n");
}
// free memory
free(matrix);
return 0;
}
4. Functions
We put this function on above main() function. Then, we can call this function, for
instance foo().
For illustration, we can create a file, called funcdemo.c , and write this code.
#include <stdio.h>
void foo(){
printf("foo() was called\n");
}
We also can declare a function on below of main() function but we must declare our
function name.
Add this code on funcdemo.c file.
#include <stdio.h>
// implicit declaration for functions
void boo();
int main(int argc, const char* argv[]) {
boo();
return 0;
}
void boo(){
printf("boo() was called\n");
}
If we compile and run this code, we will get a response, shown in Figure below.
5. I/O Operations
You can see the program output in the following Figure below.
float dec;
printf("Please enter an integer value: ");
scanf("%d", &num );
// %c ignores space characters
printf("Please enter a character: ");
scanf(" %c", &c );
printf("Please enter a city name (no space): ");
scanf("%s", city );
printf("Please enter a decimal value: ");
scanf("%f", &dec );
printf("\n-----result-------\n");
printf("number = %d\n", num );
printf("character = %c\n", c );
printf("city name = %s\n", city );
printf("decimal number = %f\n", dec );
}
return 0;
}
For testing, we create data into a file, demo.txt. For implementation, create a file, called
filewrite.c, and write this code.
#include <stdio.h>
int main(int argc, const char* argv[]) {
int i;
FILE *f;
f = fopen("demo.txt", "w+");
for(i=0;i<5;i++){
fprintf(f, "fprintf message %d\n",i);
fputs("fputs message\n", f); // no format
}
fclose(f);
printf("Data was written into a file\n");
return 0;
}
If success, it will generate demo.txt. You can open this file using text editor.
6. String Operations
Compile and run this program. If success, you get the following of program output.
7. Building C Library
To access our static library, we create a simple app. Create a file, called mysimpletest.c,
and write this code.
#include <stdio.h>
#include "mysimple.h"
int main(int argc, const char* argv[]) {
int a,b,c;
a = 5;
b = 3;
c = add(a,b);
printf("%d + %d = %d\n",a,b,c);
c = subtract(a,b);
printf("%d - %d = %d\n",a,b,c);
c = multiply(a,b);
printf("%d * %d = %d\n",a,b,c);
return 0;
}
Consider our static library, libmysimple.a , and header file for library, mysimple.h are
located into the same folder. Now you can compile and run this program.
$ gcc -I./ -L./ -o mysimpletest mysimpletest.c ./libmysimple.a
$ ./mysimpletest
To test our shared library, we can use the same program from mysimpletest.c .
Consider share library, libmysimple.so, and header file for shared library, mysimple.h,
are located on the same folder.
You can compile and run our program.
$ gcc -I./ -L./ -o mysimpletest mysimpletest.c -lmysimple
$ ./mysimpletest
Program output:
You can modify shared library file location. For instance, we put our shared library file
into /home/agusk/lib. We must add our library folder into LD_LIBRARY_PATH. Type
this command.
export LD_LIBRARY_PATH=/home/agusk/lib:$LD_LIBRARY_PATH
8. Threading
Note:
pthread_attr_t is thread attributes
start_routine is a function that will be executed
arg is argument that passes to function
For illustration, we create a thread by creating a file, called createthread.c. Write this
code.
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <errno.h>
void* perform(void *arg)
{
int i;
int *n = (int *)arg;
printf("processing from thread\r\n");
for(i=0;i<(*n);i++)
{
printf("%d ",i);
}
printf("\r\n");
}
int main(int argc, char* argv[])
{
pthread_t thread;
int ret;
errno = 0;
int n = 10;
You can see we pass parameter n=10 to function perform(). On function perform(), we just
do looping.
Now save this code. To compile and link, you can type the following command.
$ gcc -pthread -o createthread createthread.c
8.2 Thread ID
We can obtain the running thread using pthread_self() and following is its syntax.
#include <pthread.h>
pthread_t pthread_self (void);
To use this function, you can call pthread_self() inside thread function.
For illustration, create file, called threadid.c, and write this code.
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <errno.h>
void* perform(void *arg)
{
int i;
int *n = (int *)arg;
pthread_t tid;
printf("processing from thread\r\n");
/* get the calling thread's ID */
tid = pthread_self();
printf("Thread id: %d \r\n",(int)tid);
for(i=0;i<(*n);i++)
{
printf("%d ",i);
}
printf("\r\n");
}
int main(int argc, char* argv[])
{
pthread_t thread;
int ret;
errno = 0;
int n = 10;
ret = pthread_create (&thread, NULL, perform, &n);
if (ret)
{
printf("\n pthread_create() failed with error [%s]\n",strerror(errno));
return -1;
}
int c = getchar(); // hold app to exit
return 0;
}
For illustration, we build app based threading and call function perform(). On function
perform(), we do looping and will exit from internal thread after looped index 3 by calling
pthread_exit().
To implement, we create a file, called selfexit.c, and write this code.
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <errno.h>
void* perform(void *arg)
{
int i;
int *n = (int *)arg;
printf("processing from thread\r\n");
for(i=0;i<(*n);i++)
{
if(i==3)
{
printf("Terminating thread\r\n");
/* exit this thread */
pthread_exit((void *)0);
}
printf("%d ",i);
}
printf("\r\n");
}
int main(int argc, char* argv[])
{
pthread_t thread;
int ret;
errno = 0;
int n = 10;
ret = pthread_create (&thread, NULL, perform, &n);
if (ret)
{
printf("\n pthread_create() failed with error [%s]\n",strerror(errno));
return -1;
}
int c = getchar(); // hold app to exit
return 0;
}
For illustration, we build app to create a thread and try to terminate it using
pthread_cancel().
Create a file, called terminateother.c, and write this code.
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
void* perform(void *arg)
{
int n = 0;
// I'm not ready to be canceled
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
printf("processing from thread\r\n");
while(1)
{
printf("%d ",n);
n++;
pthread_testcancel();
if(n>5)
{
// I'm ready to be canceled
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
}
sleep(1);
}
printf("\r\n");
}
int main(int argc, char* argv[])
{
pthread_t thread;
int ret, status;
errno = 0;
ret = pthread_create (&thread, NULL, perform, NULL);
if (ret)
{
printf("\n pthread_create() failed with error [%s]\n",strerror(errno));
return -1;
}
sleep(10);
errno = 0;
status = pthread_cancel(thread);
if (status)
{
printf("\n pthread_cancel() failed with error [%s]\n",strerror(errno))
return -1;
}
int c = getchar(); // hold app to exit
return 0;
}
Explanation:
On main entry main(), we create a thread with passing perform()
function
We hold current process using sleep() for 10 seconds
After that, we try to terminate a thread by calling pthread_cancel()
pthread_cancel() function returns status value. You can verify this
return value
On perform() function, firstly we call pthread_setcancelstate() to
disable the thread cancelling
After looping n>5, we enable the thread cancelling
pthread_testcancel() function is called to create a cancellation
point
We need to pass thread attribute to enable joining thread. We can use pthread_attr_init(),
pthread_attr_setdetachstate(), and pthread_attr_destroy() that can be defined as follows.
#include <pthread.h>
int pthread_attr_init(pthread_attr_t *attr);
int pthread_attr_destroy(pthread_attr_t *attr);
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
For illustration, we build a simple thread app to compute a simple math equation.
Create a file, called jointhread.c, and write this code.
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <math.h>
{
pthread_t thread[5];
pthread_attr_t attr;
void *status;
int i, ret;
errno = 0;
// thread attribute
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
for(i=0;i<5;i++)
{
ret = pthread_create (&thread[i], &attr, compute, NULL);
if (ret)
{
printf("\n pthread_create() failed with error [%s]\n",strerror(errno
return -1;
}
}
sleep(2);
// joining thread
printf("joining thread\r\n");
for(i=0;i<5;i++)
{
ret = pthread_join(thread[i], &status);
if (ret)
{
printf("\n pthread_join() failed with error [%s]\n",strerror(errno))
return -1;
}
printf("Completed join with thread %ld. Status: %ld\n", i,(int)status)
}
int c = getchar(); // hold app to exit
return 0;
}
Explanation:
On main() entry point, we initialize thread attribute using
pthread_attr_init() and pthread_attr_setdetachstate() to activate
joining thread
We create 5 threads using pthread_create()
After 2 seconds, we call pthread_join() to wait 5 exiting threads
On computer() function, we calculate simple math
If finished, it call pthread_exit()
Save this code. Because we use math.h, we add library -lm on compiling and linking. The
following is a syntax to compile this code.
$ gcc -pthread -o jointhread jointhread.c -lm
$ ./jointhread
Now you can run it. The sample output is shown Figure below.
Note:
pthread_mutex_init() initialize mutex object
pthread_mutex_destroy() destroy mutex object
pthread_mutex_lock() locak mutex object
pthread_mutex_lock() unlock/release mutex object
For implementation, we create a file, called mutex.c. Firstly we define headers and global
variables. Write this code.
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
pthread_t thread[5];
int total_finished_jobs;
pthread_mutex_t lock;
total_finished_jobs = 0;
if (pthread_mutex_init(&lock, NULL) != 0)
{
printf("\n pthread_mutex_init() failed with error [%s]\n",strerror(err
return 1;
}
for(i=0;i<5;i++)
{
ret = pthread_create (&thread[i], NULL, perform_job, NULL);
if (ret)
{
printf("\n pthread_create() failed with error [%s]\n",strerror(errno
return -1;
}
}
int c = getchar(); // hold app to exit
pthread_mutex_destroy(&lock);
return 0;
}
Now save all code. You can compile and run it.
You can see a sample output on the following Figure.
8.6.1 Signaling
The idea of signaling is after you access a resource you must notify to another thread to
start accessing resource. To implement it, we can use the following functions.
#include <pthread.h>
int pthread_cond_init(pthread_cond_t *restrict cond,
const pthread_condattr_t *restrict attr);
int pthread_cond_wait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex);
int pthread_cond_destroy(pthread_cond_t *cond);
To notify another thread, you can use pthread_cond_signal() which is defined as below.
#include <pthread.h>
int pthread_cond_signal(pthread_cond_t *cond);
For illustration, we create two threads that act as producer and consumer. Producer can
write data and consumer can only read data. The data can be accessed by one thread,
either producer or consumer.
Lets start to create a file, called condvariable.c. Firstly we define headers and global
variables.
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#define BUFF_LEN 30
int buffer[BUFF_LEN];
int index_put=0, index_get=0;
int count = 0;
pthread_cond_t empty, get;
pthread_mutex_t lock;
On main() entry point, we initialize object mutex and condition variables (empty and fill).
We also create 2 thread, producer and consumer.
int main(int argc, char* argv[])
{
pthread_t thread_consumer, thread_producer;
int ret;
errno = 0;
int loops = 15;
// initialization
if (pthread_mutex_init(&lock, NULL) != 0)
{
printf("\n pthread_mutex_init() failed with error [%s]\n",strerror(err
return 1;
}
if (pthread_cond_init(&empty, NULL) != 0)
{
printf("\n pthread_cond_init() failed with error [%s]\n",strerror(errn
return 1;
}
if (pthread_cond_init(&get, NULL) != 0)
{
printf("\n pthread_cond_init() failed with error [%s]\n",strerror(errn
return 1;
}
// create thread
ret = pthread_create (&thread_consumer, NULL, consumer, &loops);
if (ret)
{
printf("\n pthread_create() failed with error [%s]\n",strerror(errno));
return -1;
}
ret = pthread_create (&thread_producer, NULL, producer, &loops);
if (ret)
{
printf("\n pthread_create() failed with error [%s]\n",strerror(errno));
return -1;
}
int c = getchar(); // hold app to exit
pthread_mutex_destroy(&lock);
pthread_cond_destroy(&empty);
pthread_cond_destroy(&get);
return 0;
}
On producer() function we do looping until obtain signal empty. After obtained a signal,
we add a value on array buffer. If done, it will notify signal get.
void *producer(void *arg)
{
int i;
int *loops = (int *)arg;
for (i = 0; i < (*loops); i++)
{
pthread_mutex_lock(&lock);
while (count == BUFF_LEN)
pthread_cond_wait(&empty, &lock);
buffer[index_put] = i;
index_put = (index_put + 1) % BUFF_LEN;
count++;
pthread_cond_signal(&get);
pthread_mutex_unlock(&lock);
}
printf("exit from producer\r\n");
}
On consumer() function, firstly we wait signal fill. After obtained signal, we read data
from array buffer. If done, we notify signal empty.
void *consumer(void *arg)
{
int i;
int *loops = (int *)arg;
for (i = 0; i < (*loops); i++)
{
pthread_mutex_lock(&lock);
while (count == BUFF_LEN)
pthread_cond_wait(&get, &lock);
int tmp = buffer[index_get];
index_get = (index_get + 1) % BUFF_LEN;
count--;
printf("Value: %d\r\n", tmp);
pthread_cond_signal(&empty);
pthread_mutex_unlock(&lock);
}
printf("exit from consumer\r\n");
}
8.6.2 Broadcasting
We can notify some threads using broadcasting signal. It can use
pthread_cond_broadcast() and defined as follows.
#include <pthread.h>
int pthread_cond_broadcast(pthread_cond_t *cond);
To start, we create a file, called broadcast.c. Firstly, we define headers and global
variables. Write this code.
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#define BUFF_LEN 30
int buffer[BUFF_LEN];
int index_put=0, index_get=0;
int count = 0;
pthread_cond_t empty, get;
pthread_mutex_t lock;
On main() entry point, we initialize mutex and condition variables. Then we create a
producer thread and 2 consumer threads.
int main(int argc, char* argv[])
{
pthread_t thread_consumer[2], thread_producer;
int ret;
errno = 0;
int loops = 15;
// initialization
if (pthread_mutex_init(&lock, NULL) != 0)
{
printf("\n pthread_mutex_init() failed with error [%s]\n",strerror(err
return 1;
}
if (pthread_cond_init(&empty, NULL) != 0)
{
printf("\n pthread_cond_init() failed with error [%s]\n",strerror(errn
return 1;
}
if (pthread_cond_init(&get, NULL) != 0)
{
printf("\n pthread_cond_init() failed with error [%s]\n",strerror(errn
return 1;
}
// create thread
ret = pthread_create (&thread_consumer[0], NULL, consumer, &loops);
if (ret)
{
printf("\n pthread_create() failed with error [%s]\n",strerror(errno));
return -1;
}
ret = pthread_create (&thread_consumer[1], NULL, consumer, &loops);
if (ret)
{
printf("\n pthread_create() failed with error [%s]\n",strerror(errno));
return -1;
}
ret = pthread_create (&thread_producer, NULL, producer, &loops);
if (ret)
{
printf("\n pthread_create() failed with error [%s]\n",strerror(errno));
return -1;
}
int c = getchar(); // hold app to exit
pthread_mutex_destroy(&lock);
pthread_cond_destroy(&empty);
pthread_cond_destroy(&get);
return 0;
}
On producer() function, we insert data after obtained signal empty. Then we call
pthread_cond_broadcast() to notify all consumer threads.
void *producer(void *arg)
{
int i;
int *loops = (int *)arg;
for (i = 0; i < (*loops); i++)
{
pthread_mutex_lock(&lock);
while (count == BUFF_LEN)
pthread_cond_wait(&empty, &lock);
buffer[index_put] = i;
index_put = (index_put + 1) % BUFF_LEN;
count++;
pthread_cond_broadcast(&get); //broadcast to consumer
pthread_mutex_unlock(&lock);
}
printf("exit from producer\r\n");
}
On consumer() function, we get data from array after obtained signal get. After that, we
notify producer thread using pthread_cond_signal().
void *consumer(void *arg)
{
int i;
Save all code. Now you can compile and run it.
The following is a sample output.
9. Database Programming
9.2 MySQL
To install MySQL server and client in Ubuntu and its database driver for C, you can try to
writ this command in terminal
$ sudo apt-get install mysql-server mysql-client
$ sudo apt-get install libmysqlclient-dev
Program output:
MYSQL_STMT *stmt;
stmt = mysql_stmt_init(con);
if (!stmt)
{
printf(" mysql_stmt_init(), out of memory\r\n");
exit(0);
}
if (mysql_stmt_prepare(stmt, CREATE_DATA, strlen(CREATE_DATA)))
{
printf("mysql_stmt_prepare(), INSERT failed\r\n");
printf("error: %s\r\n", mysql_stmt_error(stmt));
exit(0);
}
int i;
time_t now = time(NULL);
char name[10];
unsigned long str_length;
float price;
MYSQL_BIND bind[3];
MYSQL_TIME ts;
memset(bind, 0, sizeof(bind));
bind[0].buffer_type= MYSQL_TYPE_VAR_STRING;
bind[0].buffer= (char *)&name;
bind[0].is_null= 0;
bind[0].length= &str_length;
bind[1].buffer_type= MYSQL_TYPE_FLOAT;
bind[1].buffer= (char *)&price;
bind[1].is_null= 0;
bind[1].length= 0;
bind[2].buffer_type= MYSQL_TYPE_DATETIME;
bind[2].buffer= (char *)&ts;
bind[2].is_null= 0;
bind[2].length= 0;
// bind parameters
if (mysql_stmt_bind_param(stmt, bind))
{
printf("mysql_stmt_bind_param() failed\r\n");
printf("%s\r\n", mysql_stmt_error(stmt));
exit(0);
}
for(i=1;i<=10;i++)
{
// set values
sprintf(name,"product-%d",i);
str_length = strlen(name);
price = 0.23*i;
// time_t to MYSQL_TIME
struct tm *now_struct = gmtime(&now);
ts.year = now_struct->tm_year + 1900;
ts.month = now_struct->tm_mon + 1;
ts.day = now_struct->tm_mday;
ts.hour = now_struct->tm_hour;
ts.minute = now_struct->tm_min;
ts.second = now_struct->tm_sec;
printf("executing data %d\r\n",i);
if (mysql_stmt_execute(stmt))
{
printf("mysql_stmt_execute(), 1 failed\r\n");
printf("%s\r\n", mysql_stmt_error(stmt));
exit(0);
}
}
printf("done.\r\n");
printf("closing connection\r\n");
/* Close the statement */
if (mysql_stmt_close(stmt))
{
printf("failed while closing the statement\r\n");
printf("%s\r\n", mysql_stmt_error(stmt));
exit(0);
}
mysql_close(con);
printf("closed.\r\n");
exit(0);
}
Program output:
Program output:
{
printf("mysql_stmt_bind_param() failed\r\n");
printf("%s\r\n", mysql_stmt_error(stmt));
exit(0);
}
// set updated values
// change these values!!
sprintf(name,"product-updated");
str_length = strlen(name);
price = 10.33;
product_id = 5;
printf("updating data\r\n");
if (mysql_stmt_execute(stmt))
{
printf("mysql_stmt_execute(), 1 failed\r\n");
printf("%s\r\n", mysql_stmt_error(stmt));
exit(0);
}
printf("done.\r\n");
printf("closing connection\r\n");
/* Close the statement */
if (mysql_stmt_close(stmt))
{
printf("failed while closing the statement\r\n");
printf("%s\r\n", mysql_stmt_error(stmt));
exit(0);
}
mysql_close(con);
printf("closed.\r\n");
exit(0);
}
Program output:
if (con == NULL)
{
fprintf(stderr, "%s\n", mysql_error(con));
exit(1);
}
printf("connecting to mysql server\r\n");
// change host, username, and password
if (mysql_real_connect(con, "localhost", "root", "password",
"mydatabase", 0, NULL, 0) == NULL)
{
printf("error: %s\r\n", mysql_error(con));
mysql_close(con);
exit(1);
}
printf("connected.\r\n");
MYSQL_STMT *stmt;
stmt = mysql_stmt_init(con);
if (!stmt)
{
printf(" mysql_stmt_init(), out of memory\r\n");
exit(0);
}
if (mysql_stmt_prepare(stmt, DELETE_DATA, strlen(DELETE_DATA)))
{
printf("mysql_stmt_prepare(), UPDATE failed\r\n");
printf("error: %s\r\n", mysql_stmt_error(stmt));
exit(0);
}
int i;
MYSQL_BIND bind[1];
int product_id;
memset(bind, 0, sizeof(bind));
bind[0].buffer_type= MYSQL_TYPE_LONG;
bind[0].buffer= (char *)&product_id;
bind[0].is_null= 0;
bind[0].length= 0;
// bind parameters
if (mysql_stmt_bind_param(stmt, bind))
{
printf("mysql_stmt_bind_param() failed\r\n");
printf("%s\r\n", mysql_stmt_error(stmt));
exit(0);
}
// select product id to be deleted
Program output:
This chapter explains how to get started with Socket programming using C.
We also can get our hostname by program. We can use gethostname() function. It is
defined as below.
#include <unistd.h>
int gethostname(char *name, size_t len);
For illustration, we create a simple app to read local hostname. Create a file, called
gethostname.c, and write this code.
#include <stdio.h>
#include <sys/unistd.h>
int main(void)
{
char hostname[128];
gethostname(hostname, sizeof(hostname));
printf("My local hostname: %s\n", hostname);
return 0;
}
10.2.1 Server
To build server, you can follow steps, shown in Figure below.
#include <unistd.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
int listen(int sockfd, int backlog);
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
int close(int fd);
For implementation, we build server app by creating a file, called simple_server.c, and
write this code.
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
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <errno.h>
int main(void)
{
int sockfd, newsockfd, portno, clilen;
struct sockaddr_in serv_addr, cli_addr;
portno = 8056; // server port
errno = 0;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
printf("\n socket() failed with error [%s]\n",strerror(errno));
return -1;
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
10.2.2 Client
To connect the server, we can use connect() function. This function can be defined as
below.
#include <sys/types.h>
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <errno.h>
int main(void)
{
int sockfd, portno;
struct sockaddr_in serv_addr;
struct hostent *server;
// server hostname. You can change it
char server_hostname[] = "ubuntu15";
portno = 8056; // server port
errno = 0;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
printf("\n socket() failed with error [%s]\n",strerror(errno));
return -1;
}
printf("socket has created\n");
server = gethostbyname(server_hostname);
if (server == NULL)
{
printf("\n gethostbyname() failed with error [%s]\n",strerror(errno
return -1;
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(portno);
printf("connecting to server.\n");
if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr))
{
printf("\n connect() failed with error [%s]\n",strerror(errno));
return -1;
}
printf("connected to server\n");
54
55
56
57
58
// close socket
close(sockfd);
return 0;
}
10.2.3 Testing
Now we can test our server and client app. Firstly we run server app. The following is a
sample output.
These functions are general I/O functions. We can use specific I/O for socket operations
using send() and recv() functions. They can implemented as follows.
#include <sys/types.h>
#include <sys/socket.h>
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
In this section we build client-server like section 10.2 but we try to transfer data using
write() and read() functions.
10.3.1 Server
After client connected, we read data from client using read() function. Then we send
message to client using write() function. After that, we close connection.
For implementation, we create a file, called data_server.c, and write this code.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <errno.h>
int main(void)
{
int sockfd, newsockfd, portno, clilen, sz;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
portno = 8059; // server port
errno = 0;
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
close(newsockfd);
close(sockfd);
return 0;
}
This code is similar to code on section 10.2.1 but we continue to read and send data.
Save this code and compile it.
$ gcc -o data_server data_server.c
10.3.2 Client
On client side, we send message after connected. Then we read message from server.
Lets start to create a file, called data_client.c, and write this code.
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
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <errno.h>
int main(void)
{
int sockfd, portno, sz;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
// server hostname. You can change it
char server_hostname[] = "ubuntu15";
portno = 8059; // server port
errno = 0;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
printf("\n socket() failed with error [%s]\n",strerror(errno));
return -1;
}
printf("socket has created\n");
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
server = gethostbyname(server_hostname);
if (server == NULL)
{
printf("\n gethostbyname() failed with error [%s]\n",strerror(errno
return -1;
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(portno);
printf("connecting to server.\n");
if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr))
{
printf("\n connect() failed with error [%s]\n",strerror(errno));
return -1;
}
printf("connected to server\n");
// write data
strcpy(buffer,"this is message from client");
sz = write(sockfd,buffer,strlen(buffer));
if (sz < 0)
{
printf("\n write() failed with error [%s]\n",strerror(errno));
return -1;
}
// read data
bzero(buffer,256);
sz = read(sockfd,buffer,255);
if (sz < 0)
{
printf("\n read() failed with error [%s]\n",strerror(errno));
return -1;
}
printf("Received message: %s\n",buffer);
// close socket
close(sockfd);
return 0;
}
10.3.3 Testing
We are ready to test our client-server app. Firstly we run server app.
The following is a sample output for server app.
Then we run client app. You can see the output, shown in Figure below.
Contact