Quantcast
Channel: C Programming Archives - QnA Plus
Viewing all 93 articles
Browse latest View live

C Program to Find the Shortest Word in a String

$
0
0

A word is a consecutive non-whitespace character set. The C program here will find out the shortest word in a given string. If multiple words are present with the same length of the shortest one, it will print the first one.

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

#define MAX_STRING_LEN 1024

int main(){
  char str[MAX_STRING_LEN];
  char shortest_str[MAX_STRING_LEN];
  int len;
  int i, index = 0;
  int min_wlen = 0, wlen = 0;
  
  printf("Enter a string: ");
  gets(str);
  
  len = strlen(str);
  
  for (i = 0; i <= len; i++) {
  
    if (str[i] != ' ' && str[i] != '\0') {
      wlen++;
      continue;
    }
    
    if (min_wlen == 0 || wlen < min_wlen) {
      min_wlen = wlen;
      index = i - min_wlen;
    }
    
    wlen = 0;
  }
  
  for (i = 0; i < min_wlen; i++) {
    shortest_str[i] = str[index+i];
  }
  
  shortest_str[i] = '\0';
  
  printf ("Shortest word: %s.\n", shortest_str);
  printf ("Shortest word length: %d.\n", min_wlen);
  return 1;
}

This program takes a string as input. The first ‘for‘ loop traverses all the characters in the string. This loop has one extra iteration than the length of the string – to consider the last word.

The wlen variable tracks the current word length and min_wlen tracks the shortest word length so far.

For every non-whitespace character, the current word length, wlen, is increased by 1.

A whitespace character is considered as a possible end of a word – unless the previous character is also a whitespace.

If a whitespace character is encountered and the current word is shorter than the shortest word so far (wlen < max_wlen), current word length is set as the shortest one. The index variable is set as the starting index of the shortest word so far. For every whitespace character wlen is reset to o – to start a fresh count for the next word.

When the first loop ends, the index becomes the starting index of the shortest word. And min_wlen becomes the length of the shortest word.

The second ‘for‘ loop copies the shortest word to another string, shortest_str. At the end the program prints the shortest word with it length.

The program output:

$ ./test
Enter a string: Simplicity is the soul of efficiency
Shortest word: is.
Shortest word length: 2.

The post C Program to Find the Shortest Word in a String appeared first on QnA Plus.


C “Hello, World” Program

$
0
0

The iconic “Hello, World” program simply prints the message “Hello, World” on the screen. Brian Kernighan used it as a very simple C example program in late 70’s. It became popular since then. Many use this as a first program to learn a new programming language. It is also used check the readiness of a development environment – whether the IDE, the compiler, the run-time environment etc. are all in place.

The “Hello, World” Program

#include <stdio.h>
main() {
  printf("Hello, World\n");
}

Output:

$ cc test.c -o test
$ ./test
Hello, World

Recent C compilers don’t support the main() function without a return type. If we don’t specify, then the return type is assumed to an integer. This is a small variation of the same “Hello, World” program.

#include <stdio.h>
int main() {
  printf("Hello, World\n");
  return 0;
}

The “Hello, World” program is often used by the programmer to understand the basic build blocks of a programming language. This program varies significantly from language to language though. For many scripting languages, it is just a single line – and for others it’s a set of instructions.

“Hello, World” Program Components

Let’s have a look at the various parts of this C “Hello, World” Program.

The program starts with an include directive. It is a preprocessor to include the content of another file. Here we included “stdio.h” header file where all the standard input/output related function declarations are available. The used printf() is one such function.

The next few lines defined the function main(). The main() function is considered as the entry point of a C program. A C program can have many functions but the execution always starts from the main(). Unless we use some trick to execute other functions before main().

The function starts with a return type stating that the function will return an integer. Then comes the name of the function with a open brace to signify the start of a function.

The first statement is the printf() function call to print a message provided to the function. Here we provided the “Hello, World” string to print.

Next is a return statement to return the status of the program. Generally for successful execution, main() returns 0, otherwise a no-zero value to signify the failure code.

You might wonder who will catch the return value from the main(). Various execution environments start an executable and make use of the return value from main(). For example, in Linux systemd can start a Linux daemon by calling an executable. And can take action based on the return value – like if the executable returns a no-zero value, restart the program after some time.

And finally the program ends with a closing brace to signify the end of the main() function.

The post C “Hello, World” Program appeared first on QnA Plus.

C Program to Print the Current File Name and Line Number

$
0
0

Real life programs are generally very big distributed across many files with hundreds of lines. Sometimes we need to print the current file name and the line number. Like, it greatly helps the developers if we print the file name and line number with debug logs.

To do that, you can embed hard coded the file in the code. But the file name can get changed in future. Then you have to change all occurrences of the file name used in the file. Also you’ll not be able to have a common code that will be used across files that prints the current file name.

It is even more complicated for line numbers. It is almost impossible to print the line number of an instruction. Line numbers get changed so frequently as we edit the file.

Good news is that C programming language has some preconfigured macros for this purpose. The __FILE__ and __LINE__ preprocessors expand the current fine name and line number respectively.

#include <stdio.h>

int main(){
  printf("some operations.\n");
  printf("file name: %s, line number = %d.\n", __FILE__, __LINE__);
  printf("some more operations.\n");
  printf("file name: %s, line number = %d.\n", __FILE__, __LINE__);
}

This program has two exact same lines – printing the file name and the line number. The __FILE__ macro is expanded as a string with the current file name. Similarly, the __LINE__ is expanded as an integer with the current line number.

$ cc test.c -o test
$ ./test
some operations.
file name: test.c, line number = 5.
some more operations.
file name: test.c, line number = 7.

As the printf statements are used in the same file, they printed the same file name, test.c. But they printed two different line numbers, 5 and 7, as they are used in line 5 and 7.

The post C Program to Print the Current File Name and Line Number appeared first on QnA Plus.

C Program | Log with File Name and Line Number

$
0
0

Logging is an essential part of programming. Logging helps tracking various events, errors, troubleshooting. It helps the developers to great extent troubleshooting a problem if the file name and line number are also added with the log messages.

In this article, we discussed how we can add file name and line number with a message. We can add __FILE__ and __LINE__ in every message. It is a bit cumbersome and error prone also.

But we can think of a function that will print the input message along with the file name and line number. Here the problem is that the file name or line number will be of the logging function – not of the message we want to log.

But we can help of macros.

#include <stdio.h>

#define LOG_MSG(msg) { \
  printf("%s [%s:%d]\n", msg, __FILE__, __LINE__); \
}

This macro, LOG_MSG, prints the input message along with the file name and line number. It will get expanded in the place of usage. So, it will print the information of the file where it will be used.

I intentionally wrote this macro in a separate file. log.h. If I use this macro from another file (test.c), the file name and line number will be of the test.c file.

#include "log.h"

int main(){
  LOG_MSG ("log message 1.");
  LOG_MSG ("log message 2.");
}
$ cc test.c -o test
$ ./test
log message 1. [test.c:4]
log message 2. [test.c:5]

This output clearly shows that the macro, LOG_MSG, adds the file name and line number of the test.c file.

The post C Program | Log with File Name and Line Number appeared first on QnA Plus.

C Program to Implement Queue Using Circular Array

$
0
0

Queue is one of the fundamental data structures used in computer science. As the very nature of a queue, whoever comes first will be served first. That’s why it is called First In First Out (FIFO) data structure. Event Queue or Message Queue are very common examples of this data structure. We’ll see here how to implement queue using array – even though it can be implement in various other ways.

We’ll implemented the queue as a circular array. Otherwise, the number of the enqueue (described later) operations will be limited to the the array size. The array indexes will come back to the front of the array if they exceed the array size.

Queue Operations

Here are the basic queue operations.

  1. Enqueue: Inserting a new element into the queue. This newly inserted element will be the last element to be served. But it will be served before any future element that will be enqueued later.
  2. Dequeue: Get the element from the queue which came first. The retrieved element will be removed from the queue.
  3. Peek: This is same as dequeue but the element will not be removed. That means that the consecutive peek operations will give the same element.

Queue Implementation

Here the queue is represented as a structure with the following elements.

  1. An array to hold the queue elements.
  2. A counter to hold the number of elements in the queue in a particular moment.
  3. The front index to represent the position in the array where the next enqueued element will be placed.
  4. The rear index that points the last inserted element in the array.

The queue operations are implemented as functions. The functions take a queue pointer as input. This will allow to use multiple queues in the program.

Enqueue Operation Logic

  1. If the number of elements is greater than the array size, return failure. The queue is already full – no room for new element.
  2. Place the new element where the front index is pointing to.
  3. Increment the front index. If the front index exceeds the array size, it will again start from the front of the array.

Dequeue Operation Logic

  1. If the element count is 0, return failure. The queue is empty.
  2. Return the element of the rear index.
#include <stdio.h>

#define SIZE 64

struct queue {
  int element[SIZE];
  int element_count;
  
  int front;
  int rear;
};

void initialize(struct queue *q) {
  /* Sanity check */
  if (q == NULL) return;
  
  q->element_count = 0;
  q->front = 0;
  q->rear = 0;
}

int enqueue(struct queue *q, int data) {
  /* Sanity check */
  if (q == NULL) return -1;
  
  if (q->element_count >= SIZE) {
    printf("Queue is full.\n");
    return -1;
  }
  
  q->element[q->front] = data;
  q->element_count++;

  q->front = (q->front + 1) % SIZE;
}

int dequeue(struct queue *q) {
  int data;

  if (q == NULL || q->element_count == 0) {
    printf("Queue is empty.\n");
    return -1;
  }
  
  data = q->element[q->rear];
  q->element_count--;

  q->rear = (q->rear + 1) % SIZE;
  
  return data;
}

int peek(struct queue *q) {
  int data;

  if (q == NULL || q->element_count == 0) {
    printf("Queue is empty.\n");
    return -1;
  }
  
  return q->element[q->rear];
}

void display(struct queue *q) {
  int data;
  int i;
  if (q == NULL || q->element_count == 0) {
    printf("Queue is empty.\n");
    return;
  }
  
  for (i = 0; i < q->element_count; i++) {
    printf("%d ", q->element[(q->rear + i) % SIZE]);
  }
  
  printf("\n");
}

int main(){
  struct queue q;
  int data;
  int repeat = 1;
  int choice;
  
  initialize(&q);
  
  while(repeat) {
    printf("\nOptions: \n");
    printf(" 1. Enqueue \n");
    printf(" 2. Dequeue \n");
    printf(" 3. Peek \n");
    printf(" 4. Display \n");
    printf(" 5. Exit \n");
    
    printf("Enter choice: ");
    scanf("%d", &choice);
    
    switch(choice) {
      case 1:
        printf("Enter a number: ");
        scanf("%d", &data);
        enqueue(&q, data);
        printf("The entered number is enqueued.\n");
        break;
      case 2:
        data = dequeue(&q);
        printf("The dequeued numner: %d.\n", data);
        break;
      case 3:
        data = peek(&q);
        printf("The peeked numner: %d.\n", data);
        break;
      case 4:
        printf("The queue elements: ");
        display(&q);
        break;
      case 5:
        repeat = 0;
        break;
      default:
        printf("Wrong choice.\n");
        break;
    }
  }
  return 0;
}

This program runs in an infinite loop. In every iteration, it asks for options like – enqueue, dequeue, peek, display or exit. Based on the choice given, it takes input or displays value or exit.

Here is a sample output.

$ cc test.c -o test
$ ./test

Options:
 1. Enqueue
 2. Dequeue
 3. Peek
 4. Display
 5. Exit
Enter choice: 1
Enter a number: 45
The entered number is enqueued.

Options:
 1. Enqueue
 2. Dequeue
 3. Peek
 4. Display
 5. Exit
Enter choice: 1
Enter a number: 64
The entered number is enqueued.

Options:
 1. Enqueue
 2. Dequeue
 3. Peek
 4. Display
 5. Exit
Enter choice: 1
Enter a number: 23
The entered number is enqueued.

Options:
 1. Enqueue
 2. Dequeue
 3. Peek
 4. Display
 5. Exit
Enter choice: 1
Enter a number: 78
The entered number is enqueued.

Options:
 1. Enqueue
 2. Dequeue
 3. Peek
 4. Display
 5. Exit
Enter choice: 4
The queue elements: 45 64 23 78

Options:
 1. Enqueue
 2. Dequeue
 3. Peek
 4. Display
 5. Exit
Enter choice: 3
The peeked numner: 45.

Options:
 1. Enqueue
 2. Dequeue
 3. Peek
 4. Display
 5. Exit
Enter choice: 2
The dequeued numner: 45.

Options:
 1. Enqueue
 2. Dequeue
 3. Peek
 4. Display
 5. Exit
Enter choice: 4
The queue elements: 64 23 78

Options:
 1. Enqueue
 2. Dequeue
 3. Peek
 4. Display
 5. Exit
Enter choice: 5

The post C Program to Implement Queue Using Circular Array appeared first on QnA Plus.

C Program to Implement Stack Using Array

$
0
0

Stack is a collection of data elements serving Last In First Out (LIFO) functionality – whichever element comes last will be removed first.

This data structure helps solve a number of real life problems. Like undo / redo functionalities, recursive function implementation, solving arithmetic equations etc.

Basic Stack Operations

Push: Inserting a new element into the stack. The new element is inserted in such a way that it will be removed first.

Pop: Removing an element from the stack. The most recently inserted element will be removed.

Peek: Returning the last inserting element without removing that from the stack.

Display: Printing all elements in the stack – most recently inserted on top.

Stack Implementation

Here we’ll see how to implement stack and its basic operations using array.

#include <stdio.h>

#define SIZE 64

struct stack {
  int element[SIZE];
  int size;
};

void initialize(struct stack *s) {
  /* Sanity check */
  if (s == NULL) return;
  
  s->size = 0;
}

int push(struct stack *s, int data) {
  /* Sanity check */
  if (s == NULL) return -1;
  
  if (s->size >= SIZE) {
    printf("Stack is full.\n");
    return -1;
  }
  s->element[s->size] = data;
  s->size++;
  
  /*Returning the current stack size...*/
  return s->size;
}

int pop(struct stack *s) {
  if (s == NULL || s->size == 0) {
    printf("Stack is empty.\n");
    return -1;
  }
  
  s->size--;
  return s->element[s->size];
}

int peek(struct stack *s) {

  if (s == NULL || s->size == 0) {
    printf("Stack is empty.\n");
    return -1;
  }
  
  return s->element[s->size - 1];
}

void display(struct stack *s) {
  int data;
  int i;
  if (s == NULL || s->size == 0) {
    printf("Stack is empty.\n");
    return;
  }
  
  for (i = s->size - 1; i >= 0; i--) {
	  printf("%d\n", s->element[i]);
  }
}

int main(){
  struct stack s;
  int data;
  int repeat = 1;
  int choice;
  
  initialize(&s);
  
  while(repeat) {
    printf("\nOptions: \n");
    printf(" 1. Push \n");
    printf(" 2. Pop \n");
    printf(" 3. Peek \n");
    printf(" 4. Display \n");
    printf(" 5. Exit \n");
    
    printf("Enter choice: ");
    scanf("%d", &choice);
    
    switch(choice) {
      case 1:
        printf("Enter a number: ");
        scanf("%d", &data);
        push(&s, data);
        printf("The entered number is pushed.\n");
        break;
      case 2:
        data = pop(&s);
        printf("The popped numner: %d.\n", data);
        break;
      case 3:
        data = peek(&s);
        printf("The peeked numner: %d.\n", data);
        break;
      case 4:
        printf("The stack elements: \n");
        display(&s);
        break;
      case 5:
        repeat = 0;
        break;
      default:
        printf("Wrong choice.\n");
        break;
    }
  }
  return 0;
}

This program is implemented in such a way that multiple stacks can be used in the program at the same time. That’s why the functions take a stack as input. They work on the input stack.

Let’s discuss on the various elements of this program.

The stack data structure is defined as a C structure consisting of an array and an integer. The array holds the stack elements and the integer is the number of stack elements.

The initialize() function: simply sets the stack size to 0.

The push() function: does the sanity checking whether the stack pointer is invalid or the stack is full. In that case it returns -1 to signify push operation is failed. Then it assign the new element at the index equal to the current stack size. Then it increases the size. So the next element will be inserted at the next index.

The pop() function: decrements the stack size. Then it returns the array element of the index equal to the changed size. It means that the next pushed element will placed at the same place.

The pop() function: same as the pop() function but the stack size is not decreased. So, this function will return the same element if it is called multiple times.

The main() function runs in a infinite loop asking for options. It then does the selected stack operation.

Here is a sample output.

$ cc test.c -o test
$ ./test

Options:
 1. Push
 2. Pop
 3. Peek
 4. Display
 5. Exit
Enter choice: 1
Enter a number: 11
The entered number is pushed.

Options:
 1. Push
 2. Pop
 3. Peek
 4. Display
 5. Exit
Enter choice: 1
Enter a number: 22
The entered number is pushed.

Options:
 1. Push
 2. Pop
 3. Peek
 4. Display
 5. Exit
Enter choice: 1
Enter a number: 33
The entered number is pushed.

Options:
 1. Push
 2. Pop
 3. Peek
 4. Display
 5. Exit
Enter choice: 1
Enter a number: 44
The entered number is pushed.

Options:
 1. Push
 2. Pop
 3. Peek
 4. Display
 5. Exit
Enter choice: 1
Enter a number: 55
The entered number is pushed.

Options:
 1. Push
 2. Pop
 3. Peek
 4. Display
 5. Exit
Enter choice: 4
The stack elements:
55
44
33
22
11

Options:
 1. Push
 2. Pop
 3. Peek
 4. Display
 5. Exit
Enter choice: 2
The popped numner: 55.

Options:
 1. Push
 2. Pop
 3. Peek
 4. Display
 5. Exit
Enter choice: 4
The stack elements:
44
33
22
11

Options:
 1. Push
 2. Pop
 3. Peek
 4. Display
 5. Exit
Enter choice: 3
The peeked numner: 44.

Options:
 1. Push
 2. Pop
 3. Peek
 4. Display
 5. Exit
Enter choice: 5

The post C Program to Implement Stack Using Array appeared first on QnA Plus.

C Program to Count Words in a File

$
0
0

We discussed different ways to count words in a file in this article. Here we’ll extend that to count all words in a file. We can think of a file as a collection of lines. We’ll count words of each line one by one and add them up.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MAX_LEN 1024

int count_word(char *str) {
  int count = 0;
  char* token = strtok(str, " ");
  while (token != NULL) {
    count++;
    token = strtok(NULL, " ");
  }

  return count;
}

int main() {
  FILE *fp;
  char *line = NULL;
  size_t len = 0;
  int count = 0;
  
  fp = fopen("sample.txt", "r");
  if (fp == NULL) return -1;

  while (getline(&line, &len, fp) != -1) {
    count += count_word(line);
  }
  
  if (line) free(line);
  
  fclose(fp);

  printf("Number of words in the file is %d.\n", count);
  return 0;
}

This program first opens the file, sample.txt, in read-only mode. The next while loop reads one line at a time using the getline() function. The read line is passed to the count_word() function that returns the number of words in the line. The returned number is added to the count variable.

The loop will terminate when there will be no line to read in the file. The count variable accumulates the word counts of each line. So, at the end of the loop it will hold the word count of the file.

The count_word() function uses strtok() function to split a line. The next loop counts the words of the line.

Here is the content of the input file.

$ cat sample.txt
All sorts of things and weathers
Must be taken in together
To make up a year
And a sphere

It has 19 words in 4 lines.

Here is the output of the above program.

$ cc test.c -o test
[polaris@localhost del]$ ./test
Number of words in the file is 19.

The post C Program to Count Words in a File appeared first on QnA Plus.

C Program to Write to a File

$
0
0

Writing to a file is a basic programming requirement. All information of a running program is generally stored in the physical memory or RAM. They are lost with the termination of the program. If you need to persist some information, you need to store it in some persistent storage like a disk. Writing to a file is a very common way of persisting data.

For example, when we write something on a notepad application and save that to a file. Whatever we wrote is basically saved to the file in text format. But when we draw something in the paint application, that can also be saved to a file in a complicated binary format.

Here we’ll see how a C program can write text to a file.

Logic to Write to a File

  • Declare a file pointer variable, FILE *fp.
  • Open a file using the fopen() function. This function takes the file name as input and the open mode. Specify the open mode as “w” for writing. The file specified by the name will be created.
  • Write to files using functions like fprintf(), fputs() etc.
  • Close the file using the fclose() function.
#include <stdio.h>
#include <stdlib.h>

#define MAX_LINE_LEN 1024

int main() {
  char name[MAX_LINE_LEN];
  int age;
  char file_name[MAX_LINE_LEN];
  
  FILE *fp;
  
  /*Taking your name and age as input. These will be saved in a file...*/
  printf("Your name: ");
  gets(name);
  printf("Your age: ");
  scanf("%d", &age);

  /*Flushing extra new line left over by previous operation...*/
  getchar();
  
  /*Taking the file name as input...*/
  printf("Enter the file name to save: ");
  gets(file_name);
  
  /*Opening the file...*/
  fp = fopen(file_name, "w");
  
  /*File open operation failed.*/
  if (fp == NULL) return -1;
  
  /*Writing your name and age into the file...*/
  fprintf(fp, "Your name: %s\n", name);
  fprintf(fp, "Your age: %d\n", age);
  
  /*Closing the file...*/
  fclose(fp);
  
  printf("Your name and age are saved to the file %s. Open and check.\n", file_name);
  return 0;
}

This program first takes a string, name, and an integer, age, as input. Then it takes the file name to save this information.

File with this name is opened in writing mode. The name and age are written to the file using the fprintf() function. At the end the file is closed.

Output of the program:

$ cc test.c -o test
$ ./test
Your name: Charges Babbage
Your age: 85
Enter the file name to save: info.txt
Your name and age are saved to the file info.txt. Open and check.

We can see a new file with the name info.txt is created in the same location we ran the program from. We can see the content written in the file.

$ cat info.txt
Your name: Charges Babbage
Your age: 85

The post C Program to Write to a File appeared first on QnA Plus.


C Program to Append to a File

$
0
0

In the previous article, we saw how to write something in a text file. In that case, the previous content, if any, will be overwritten. If there is something in the file to begin with, that content will no longer be present after the new content is written.

Here we’ll see how to add new content at the end of a file. Whatever is already present in the file will be preserved.

Logic to Append to a File

  • Declare a file pointer variable, FILE *fp.
  • Open a file using the fopen() function. This function takes the file name as input and the open mode. Specify the open mode as “w+” for writing. The file specified by the name will be opened. If the file is not present, then it will be created.
  • Write to the file using functions like fprintf(), fputs() etc.
  • Close the file using the fclose() function.

Let’s say, we have a file, info.txt, that already has this content.

$ cat info.txt
Your name: Charges Babbage
Your age: 85

Here is the program to append content at the end of the file.

#include <stdio.h>

#define MAX_LINE_LEN 1024

int main() {
  char address[MAX_LINE_LEN];
  char file_name[MAX_LINE_LEN];
  
  FILE *fp;
  
  /*Taking your address as input. These will be appended into a file...*/
  printf("Your address: ");
  gets(address);
  
  /*Taking the file name as input...*/
  printf("Enter the file name to append to: ");
  gets(file_name);
  
  /*Opening the file in appending mode...*/
  fp = fopen(file_name, "a+");
  
  /*File open operation failed.*/
  if (fp == NULL) return -1;
  
  /*Appending your address into the file...*/
  fprintf(fp, "Your address: %s\n", address);
  
  /*Closing the file...*/
  fclose(fp);
  
  printf("Your address is appended to the file %s. Open and check.\n", file_name);
  return 0;
}

This program first takes the address as input. Then it takes the name of the file. The file is opened in append mode. The provided address is appended at the end of the file.

Output of the program:

$ cc -o test test.c
$ ./test
Your address: 44 Crosby Row, Walworth Road, London, England
Enter the file name to append to: info.txt
Your address is appended to the file info.txt. Open and check.

If we check the file, we can see the new content is present in the file.

$ cat info.txt
Your name: Charges Babbage
Your age: 85
Your address: 44 Crosby Row, Walworth Road, London, England

The post C Program to Append to a File appeared first on QnA Plus.

Networking Programming – Introduction to socket

$
0
0

Computer networking programming, often referred as socket programming, is about writing programs to exchange information between processes running on connected hosts – computers, mobiles etc. Hosts are generally interconnected over a private network (LAN) or internet. In fact, the processes can run on a single host or computer also.

Most applications today, desktop or mobile, are becoming more online. They exchange information with other entities over the internet. For example, when you opened this article, your web browser, Chrome, IE or something else, exchanged information with a web server identified by ‘qnaplus.com’. Both the web browser and the web server are examples of network programs.

When we write network programming, we take help of a software framework or structure called socket. Socket allows a program to transmit and receive data to or from another program.

Network socket acts as an end point of a network communication which is generally identified as transport protocol, IP address and port. For a programmer, a socket is just an integer – socket library APIs hide all the detail. On Unix-like systems, socket is just like any other file descriptors (fd). Instead of read and write, we have send and receive type of functions to exchange information.

Here are some important concepts associated with networking programming.

Client Server Architecture

When processes communicate over a computer network, they play two distinct roles – server and client. Sever passively waits for connections from clients. The clients, on the other hand, actively initiate a connection towards the server. When the connection is established, the client requests something, like text, image or video and the server serves that.

In our web page access example, the website, ‘qnaplus.com’ acts as a server running somewhere on the internet. The server here is identified as the domain name, ‘qnaplus.com’, which eventually gets translated into an IP address and a port. The server always waits for new connection requests from the clients.

The web browser, Chrome or IE, that you are using, acts as a client. When you put the website address, ‘qnaplus.com’, on the address bar, the browser connects to a DNS (Domain Name Server) to translate it into an IP address. It uses port 80 by default for website access. Then using this IP address and the port, the browser connects the server. Once the connection is established, the client requests the home page of the website. The website name generally represents the home page of the site. The server transfers the home page over the computer network which is eventually displayed by the browser. Other pages, identified by URL (Uniform Resource Locator), can also be requested in the similar way.

Networking Protocols

Protocols are the heart of network communications. They are basically a set of rules agreed between two parties involved in data communication. Purpose of protocol varies from transferring information to security to element discovery to management etc.

Protocols primarily define the format of the data that is exchanged and how to process the received data.

Data format means which bit or byte of the transmitted data represents what. For example, the IP packet format looks like this.

IPv4 Header

The first 4 bits represent the IP version. For IPv4, the value of this field will be 4. Generally IP packets carry transport layer packets like TCP or UDP. We’ll learn about this later.

Similarly two bytes starting from the second byte represent the total length of an IP packet. Whoever will process an IP packet will know the total length of the packets.

All other header fields are defined by the IP protocol. All parties involved in IP communication will have to agree on this.

Processing a protocol packet depends on the protocol. For example, routers and network hosts process IP packets. Routers’ job is to help reach the packets to their final destinations. Routers get the destination IP address of the packet from a predefined header field and figures out the next hop for the packet.

Connectionless and Connection Oriented Transport

There is always a tradeoff between transport reliability and communication overhead. Transport protocols are categorized as connection-oriented and connectionless based on that.

Connection-Oriented

Connection oriented protocols aim for reliable data transport.

Connection establishment: Before sending any data, two parties (client and server) establish a connection. It is a kind of handshake where both parties inform each other that they are available and ready to exchange data.

Reliability: Connection oriented protocol ensures that the sent data is actually received by the receiver. The receiver sends an acknowledgement to the sender that some portion of the is actually received.

Nodrop delivery: It ensures that no portion of the transmitted data is dropped. If some data is lost on transmission, they will be retransmitted. It is achieved by having data sequence numbers and an acknowledgement mechanism.

In order delivery: Connection oriented protocols ensure that the data portions are delivered in the same order they were sent by the sender. Even if data packets are reached out of order by the lower layer protocol (say IP), they get rearranged based on the sequence number before delivering to the receiver.

Apart from these, connection oriented protocols provide flow control, congestion control, multi-homing etc.

Connectionless

On the contrary, connectionless protocols transport data on a best effort basis.

Connectionless protocols don’t establish a connection before transmitting the actual data. The sender won’t know whether the receiver actually exists or is ready to receive data.

The sender will not know whether the transmitted data is actually received by the receiver.

All transmitted packets might not be delivered.

There is no guarantee that the transmitted packets will be received by the receiver in the same order they were transmitted.

This transport mode doesn’t have overheads, bigger header or extra control packet exchange, that the connection oriented protocols have to achieve the reliability.

This is the best mode for multicasting and broadcasting.

The post Networking Programming – Introduction to socket appeared first on QnA Plus.

Bit Fields in C

$
0
0

The variable size of a standard type is always in bytes – not in fraction of bytes. For example, the size of a char type variable is 1, short type variable is 1, in type variable is 4 and so on. We can not have a variable of size half byte (4 bits) or 1 bit.

But we can keep some information in less that a byte or 8 bits. For example, the date of a month, whose value can be in the range of 1 to 31, can be kept in 5 bits. A boolean flag, whose value can be either true or false, can be kept in 1 bit.

But a boolean type variable takes 1 byte (or bits) space in memory. Any number, even if we declare it as ‘unsigned char’, takes at least 1 byte.

In some cases where we have resource limitations, saving a few bytes can make huge difference. We need to take significant effort to reduce memory consumption of a program running on low footprint embedded devices. One way to reduce a program’s memory consumption is to pack the variables as compact as possible.

In C programming, we can define bit field inside a struct or union to minimize memory requirement wherever possible. We can define a variable of size of as many bits are really required. Not that we have to allocate at least 1 byte where even 1 bit is sufficient.

Bit Fields – the Solution

Let’s consider this struct.

struct S1 {
    unsigned char flag1;  /*Range: 0-1*/
    unsigned char flag2;  /*Range: 0-1*/
    unsigned char flag3;  /*Range: 0-1*/

    unsigned char date;   /*Range: 1-31*/
    unsigned char num;    /*Range: 0-256*/
};

Here we have 5 member variables. First 3 variables, flag1, flag2 and flag3, are booleans whose value could be either 1 (true) or 0 (false). Next one is date – value could be in the range of 1 and 31. The last variable is a number ranging from 0 to 256.

We declared all variables as ‘unsigned char‘ – the data type of minimum length of 1 byte. So the size of this structure will be 5. Five variables, each with length 1.

But the whole 1 byte is not required for all the variables. The first three variable will require 1 bit each to hold o or 1. For the date variable, 5 bits are sufficient. So, the first 4 variable could be accommodated within 8 bits or 1 byte. The num variable will need one whole byte as its value can range from 0 to 256.

So the whole structure could be accommodated within 2 bytes. But it will take 5 bytes in memory in its current form.

Good news is that we can force it to take required 2 bytes. Here is the modified structure.

struct S2 {
    unsigned char flag1:1;
    unsigned char flag2:1;
    unsigned char flag3:1;

    unsigned char date:5;
    unsigned char num;
};

We can write a program to check that the size of this structure is really 2 bytes.

#include <stdio.h>

struct S2 {
    unsigned char flag1:1;
    unsigned char flag2:1;
    unsigned char flag3:1;

    unsigned char date:5;
    unsigned char num;
};

int main() {
    printf("%lu\n", sizeof(struct S2));
    return 0;
}
$ cc test.c
$ ./a.out 
2

We specified the size in bits for the variables where the whole byte is not required. The ‘:1‘ after ‘flag1‘ signifies that the size of ‘flag1‘ is 1 bit. Similarly, we specified the size of date as 5 bits.

So, we learnt the trick to save some bytes in our programs.

Things to Remember

So far all good. But we need to remember few things. Otherwise, we’ll not get the expected results.

Variable Ordering is Important

Let consider this structure.

struct S2 {
    unsigned char flag1:1;
    unsigned char flag2:1;
    unsigned char num;
    unsigned char flag3:1;

    unsigned char date:5;
};

Earlier, the variable, num, was the last variable. We put that between flag1 and flag2. You can expect that the size of this structure will be the same as before, i.e. 2. But in reality, it is of 3 bytes.

What happened here?

We can explain it this way. The first variable requires 1 bit. So, for that 1 byte is allocated as the data type is ‘unsigned char‘. Now we have 7 spare bits available. The next variable also requires 1 bit. As the first byte has 7 unused bits, the second variable is fitted there. The first byte now has 6 spare bits. But the third variable needs 8 bits. The first byte, that has 6 unused bits left, can not accommodate that. So, a new byte is allocated. The 6 unused bits of the first byte will remain unused. The last two variables require 6 bits. That’s why another byte is allocated. So, total 3 bytes are required here.

We need to mindful about the bit size as well as the ordering of variables to get best effect.

Unnamed Bit Field

C supports an unnamed struct member of size 0 to force alignment on the next boundary.

struct S2 {
    unsigned char v1:3;
    unsigned char v2:5;
};

We can rightly expect that the size of this structure is 1 byte.

struct S2 {
    unsigned char v1:3;
    unsigned char : 0;
    unsigned char v2:5;
};

But size of the above structure will be 2. 1 byte will be allocated for the first variable v1 of size 3 bit. In that byte, there will be still 5 bits left in that byte to accommodate the last variable v2. But as we have an unnamed variable with size 0 between v1 and v2, the unused bits after v1 will not be used. This unnamed variable will force to align the next variable in next boundary. As this structure is 1 byte aligned, the v2 will start at the next byte. So, whole 2 bytes will be used for this structure.

Reference of Bit-Field

We can not get reference or memory location of a bit-field variable. Reference is basically the starting byte location of a variable in memory. But a bit-field can start to locate at any position of a byte – not necessarily from the starting of the byte. That’s why compiler prevents to get the location of a bit-field variable.

#include <stdio.h>

struct S2 {
    unsigned char v1:4;
    unsigned char v2;
};

int main() {
    struct S2 s;
    
    printf("Address of v1: %p\n", &s.v1);

    return 0;
}
$ cc -o test test.c
test.c: In function ‘main’:
test.c:11:35: error: cannot take address of bit-field ‘v1’
   11 |     printf("Address of v1: %p\n", &s.v1);
      |                                   ^

But we can get the location of a non-bit-field variable of the same structure.

#include <stdio.h>

struct S2 {
    unsigned char v1:4;
    unsigned char v2;
};

int main() {
    struct S2 s;
    
    printf("Address of v2: %p\n", &s.v2);

    return 0;
}
$ cc -o test test.c
$ ./test 
Address of v2: 0x7fff7268cfb7

We need to keep in mind that if we ever need the reference of a variable, we can not make that variable a bit-field.

The post Bit Fields in C appeared first on QnA Plus.

Backpointer – Concept and Application

$
0
0

We often work with data structures with connected nodes – like trees and graphs. In a tree, the parent nodes generally hold the pointers of their child nodes. But the child nodes can also hold the pointer back to their parent. Developers often refer this type of pointers as backpointers.

backpointer

In this diagram, the black arrows are representing the normal forward pointers. In time of creating a child node, the parent node can pass its own pointer to the child node. Later, we can get hold of the parent node from the child using that pointer. The red lines are representing such type of back pointers.

Any object containing its creator’s pointer can be referred as containing a backpointer. The relationship does not have to be hierarchical.

Benefits of Backpointer

  1. Ease of traversing: Using backpointer we can traverse back and forth from parent to child and vice versa easily. For example, if all tree nodes hold their parents’ pointer, we can very easily traverse through the tree nodes easily.
  2. Accessing parent objects functionalities: The parent node does not have to be always the same type of node as the child. The parent node might have some functionalities (functions) the child might require for its own work. The child can get that via backpointers.
  3. Get access to parent’s properties: The child node can get access to the parent’s properties – value of member variables – though the backpointer.

Backpointer Implementation

#include <iostream>
using namespace std;

class node {
public:
    node(int val, node *parent = NULL) {
        val_ = val;

        parent_ = parent;
        left_child_ = right_child_ = NULL;
    }

    ~node() {
        if (left_child_) delete left_child_;
        if (right_child_) delete right_child_;
    }

    node *addLeftChild(int val) {
        left_child_ = new node(val, this);

        return left_child_;
    }

    node *addRightChild(int val) {
        right_child_ = new node(val, this);

        return right_child_;
    }

    int getVal() {
        return val_;
    }

    int getParentVal() {
        if (parent_ == NULL) return 0;

        return parent_->getVal();
    }

    node *getParent() {
        return parent_;
    }

private:
    int val_;
    node *parent_;

    node *left_child_;
    node *right_child_;
};

int main() {
    node *root = new node(10);

    node *child1 = root->addLeftChild(20);
    node *child2 = root->addRightChild(30);

    node *parent = child1->getParent();

    cout << "Parent value: " << parent->getVal() << endl;

    cout << "Parent value from child1: " << child1->getParentVal() << endl;

    return 0;
}
$ g++ -o test test.cpp 
$ ./test 
Parent value: 10
Parent value from child1: 10

In this example, we have a class, node, that can be used to construct a binary tree. It has two pointers for its two child nodes and another pointer, parent_, to hold the parents address.

The addLeftChild() or the addRightChild() function creates a child node and returns that child’s pointer. In time of creatine the child, it passes its own pointer, referred as this, to this child. The ways the child possesses it parent’s or creator’s pointer.

Now, if we have access to a child, we can easily traverse to its parent. The getParent() function returns the address of the parent. We can get the value of the parent from the returned address. The first ‘cout‘ statement showed that.

The child can also directly access the value of the parent though the backpointer, parent_. The getParentVal() function returns the parent’s value. Inside that function, the child node accessed its parent’s value via the backpointer, parent_. That’s why the second ‘cout’ state printed the same value.

The post Backpointer – Concept and Application appeared first on QnA Plus.

Multithreading in C

$
0
0

We can create multiple threads in our C program to execute multiple tasks in parallel. It helps to utilize the CPU resources efficiently. Even though core C programming does not support multithreading, at least until C11 standard, it has a lot of library support for that purpose.

POSIX thread or pthread is one of the most popular threading libraries in C on Linux.

Time Consuming Tasks

#include <stdio.h>
#include <unistd.h>

void task_1() {
    int i = 0;

    for (i = 0; i < 10; i++) {
        printf("Task 1, iteration: %d.\n", i);
        sleep(1);
    }
}

void task_2() {
    int i = 0;

    for (i = 0; i < 10; i++) {
        printf("Task 2, iteration: %d.\n", i);
        sleep(1);
    }
}

void main()
{
    task_1();
    task_2();
}
$ cc -o test test.c
$ ./test 
Task 1, iteration: 0.
Task 1, iteration: 1.
:
Task 1, iteration: 8.
Task 1, iteration: 9.
Task 2, iteration: 0.
Task 2, iteration: 1.
:
Task 2, iteration: 8.
Task 2, iteration: 9.

We have two time consuming tasks, task_1() and task_2(), in this program. Each function takes 10 seconds to complete execution and prints a message in every one second.

In main(), these two functions are called one after another. From the output, we can see that the first function, task_1(), printed 10 messages and took 10 seconds. The second function, task_2(), could not even get started until task_1() finished. There is no way to execute them in parallel unless we create multiple threads.

Create Multiple Threads to Parallelize Tasks

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>

void *task_1(void *param) {
    int i = 0;

    for (i = 0; i < 10; i++) {
        printf("Task 1, iteration: %d.\n", i);
        sleep(1);
    }
}

void *task_2(void *param) {
    int i = 0;

    for (i = 0; i < 10; i++) {
        printf("Task 2, iteration: %d.\n", i);
        sleep(1);
    }
}

void main()
{
    pthread_t thread_id1;
    pthread_t thread_id2;

    /*Create two threads to execute two task in parallel*/
    pthread_create(&thread_id1, NULL, task_1, NULL);
    pthread_create(&thread_id2, NULL, task_2, NULL);

    pthread_join(thread_id1, NULL);
    pthread_join(thread_id2, NULL);
}
$ cc -o test test.c -lpthread
$ ./test 
Task 1, iteration: 0.
Task 2, iteration: 0.
Task 1, iteration: 1.
Task 2, iteration: 1.
Task 2, iteration: 2.
:
:

We changed the program to create two threads for two of our time consuming functions. The pthread library function pthread_create() is used to create a thread.

It takes the function that will be executed in the context of the newly created thread. We passed task_1() in the first call and task_2() in the second call. The function signatures are changed a little bit to be compliant with the requirement of the pthread_create() function.

This function also takes a thread id. We can use this id later to control thread. Like we used it in the next pthread_join() calls.

The pthread_join() function waits until the specified thread completes.

From the output, we can see that the messages from two functions interleaved. That means that both the functions are getting executed in parallel from two different threads.

The pthread_create() functions return immediately after creating the threads. If we don’t call the pthread_join() functions, the main() thread will exit immediately. And you’ll not see any output. You can try that. The pthread_join() calls are also required to cleanup the resources created during thread creating.

The post Multithreading in C appeared first on QnA Plus.

Viewing all 93 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>