C Programming – Linux Hint https://linuxhint.com Exploring and Master Linux Ecosystem Tue, 09 Mar 2021 05:59:30 +0000 en-US hourly 1 https://wordpress.org/?v=5.6.2 How To Use the C Programming Language in Ubuntu 20.04 https://linuxhint.com/how-to-use-the-c-programming-language-in-ubuntu-20-04/ Sun, 07 Mar 2021 21:39:50 +0000 https://linuxhint.com/?p=93223

C is an excellent procedural programming language for beginners who want to learn how to program. Many applications, including databases and operating systems, use this general-purpose programming language for development.

The C language is popular among new learners because it is not only easy to use but also helps programmers to better understand the internal architecture of the computer. C is the first step into the programming world, and after learning the C programming language, it will not be as difficult to learn other programming languages. Moreover, the C language is portable, as programs written in this language can be transferred to various platforms without requiring any changes to the code.

This article shows you how to use the C programming language in Ubuntu 20.04 (LTS) and 20.10.

Installing and Running the C Language

To begin working with the C programming language in Ubuntu, first, you will need to install it.

To make the C language run on Ubuntu, you first need to get its compiler, which can be installed through the installation of the build-essential development package. To install this package, launch the terminal and issue the following command:

$ sudo apt install build-essential

After the installation process of the build-essential package is completed, use the following command to view the version of the C compiler:

$ gcc --version

Now that you have installed the C compiler on your system, you can get started with the C language.

Writing Code in the C Language

First, open any text editor and write a simple C program. To run the program, open a text file and write a program in the file.

Save the file, naming it “HelloLinux” with the “.c” extension. Compile the code via the command provided below:

$ gcc –o HelloLinix HelloLinuc.c

To obtain the output of the program, type the filename in the terminal:

$ ./HelloLinux.c

Conclusion

This guide showed you how to make the C programming language work in Ubuntu. The C programming language is a general-purpose language that is used to develop graphics, applications, even games. For new programmers, the C language is the first step into the software development world, since it is easy to master. Even in 2020, the C language remains popular and relevant among developers due to its ubiquity and simplicity.

]]>
POSIX Spawn with C Programming https://linuxhint.com/posix-spawn-c-programming/ Thu, 11 Feb 2021 15:33:57 +0000 https://linuxhint.com/?p=89637 Spawn is a function used in POSIX to load and execute child processes. The currently running process in POSIX will then either continue or not continue to execute these child processes and other processes asynchronously. Whenever a new sub-process is created, it requires some specific memory that will allow the parent and child process to execute. In Microsoft Windows, UNIX, and Linux, there is a certain family of spawns; and other families of spawn functions are considered an optional extension.

Why Use POSIX Spawn?

The posix_spawn() and posix_spawnp() functions are both used to create a new child process. The child process then executes a file. These functions were specified by POSIX to standardize the method of creating new processes for machines that do not have fork system call support. These machines are usually small and lack the embedded systems for lMMU support.

The two functions combine fork and exec, with some additional steps that will execute the child. They act as a subset of functionalities, usually achieved with a fork, for all the system calls and embedded systems that lack such functionality.

Example 1: posix_spawn()

In this example, we will use the spawn () function to create and execute a new child process. Then, we will explain all the relevant arguments used in the function.

The arguments used in the example are as follows:

Argument Description
<spawn.h> Used to define all spawn performing operations.
path The name of the path that is to be executed.
fd_count The number of the entries with the array of fd_map. If fd_count is equal to 0, then the fd_map is ignored. In such cases, the child process inherits all the file descriptors, ignoring the ones that were modified.
fd_map
 
An array of file descriptors to be inherited by the child process. Here, if the value of fd_count is not 0, then fd_map is needed to bring the fd_count file descriptors up to a supreme value of OPEN_MAX. It has:

·      The child process input

·      The output

·      The error values

inherit The struct inheritance shows that users want their child process to inherit everything from the parent.
argv The pointer to a particular argument vector. The argv[0] value cannot be NULL and must be the filename that is being loaded. The argv value cannot be equal to NULL.
envp Points to an array of character pointers. Each of the pointers in this array points to an environment variable. The finish point of the array is a NULL pointer.

Example 2: test.c

In the following example, a new child process is created to run the command by /bin/sh -c. This is the value passed as the first argument. The test.c code is as follows:

In the above example, we called the libraries, then called the spawn.h header. You will also see the posix_spawn() called to create a child process in the above example. The spawn and spawnp functions are used in place of the fork and exec functions. Spawn() has flexibility and provides a lot of ease to the users in many ways. It is a bit dissimilar from system() and exec(). It will return and create the fresh child process. In our example, it is pid. Above, you can see that the wait function waitpid(), then system() is used. Notice that the spawn() and fork() calling processes are the same, and the method of implementation is more or less the same for both functions.

We will now execute the example using a gcc compiler. You can also use any other compiler of your choice:

$ sudo gcc test.c -lrt

Next, run the following:

$ ./a.out

The output of the above command will look as follows:

The child pid will be created, as you can see in the above output.

Library

Libc: Use the -l c to link the gcc compiler. Here, notice that this library is included automatically.

Spawn()

The spawn() function is based on POSIX 1003.1d draft standard used as posix_spawn(). The C library includes spawn*() functions. Here, we will list a few suffixes, along with their descriptions:

e: used as an array for environment variables.

l: used as a NULL-terminated list of the arguments used inside the program.

p: used to define a relative path. If the path does not have a slash in its value, then the system uses and searches the PATH environment variable for any similar program.

v: acts as a vector of arguments inside the program.

Mapping File Descriptors

In spawn(), we practice the fd_count and fd_map arguments to call out the file descriptors. It specifies which child to inherit.

The number used as a file descriptor for the child process depends on its location inside the fd_map. Here, we will consider the example of the parent with file descriptors valued 1, 3, and 5, then the mapping will be something like this:

>> int fd_map = { 1, 3, 5 };
For the child For the parent
0 1
1 3
2 5

Note that if you are using the explicit fd_map to match these file descriptors with the child and parent, then you must map the SPWAN_FDCLOSE function to proceed.

Inheritance Flags

In Spawn, users need to call out any of the following flags in case of inheritance. Some examples of Spawn flags and their descriptions are given below:

Flag Description
SPAWN_ALIGN_DEFAULT This flag is used to set up the default settings of the setup for alignment.
SPAWN_ALIGN_FAULT This flag is used for fault misalignment of the data references.
SPAWN_ALIGN_NOFAULT This flag is used to fix the fault misalignment.
SPAWN_DEBUG This flag is used to debug the kernel.
SPAWN_EXEC SPAWN acts like exec*() using this flag.
SPAWN_EXPLICIT_CPU This flag is used to set the run mask and inherit the mask=run mask member.
SPAWN_EXPLICIT_SCHED This flag is used to set the scheduling policy.

The <spawn.h> defines that mask SPAWN_ALIGN_MASK used to align the flags listed above.

pid_t pgroup The child process group if you specify the SPAWN_SETGROUP in the flag’s member.
int runmask The runmask of the child process to inherit the masks that are agreed based on the value of this member.
sigset_t sigmask The signal mask for the child process that is used to specify the status of flag members.
sigset_t sigdefault The set of the child processes of the defaulted signals.

 Errors

The posix_spawn() and posix_spawnp() functions can also fail in some cases, such as the following:

EINVAL: This is the case when the value identified by file_actions or attrp is not correct and adequate.

When the underlying fork (2), fork (2), or clone (2) call fails, the spawn() functions will return an error number.

ENOSYS: This is the case if the function and its support is not included or provided within a system.

Conclusion

This tutorial covered the basic functionalities provided by POSIX_spawn() and the functions used by it to execute and perform its functions. We also covered the flags and errors commonly used by Spawn.

]]>
POSIX Message Queues with C Programming https://linuxhint.com/posix-message-queues-c-programming/ Wed, 10 Feb 2021 18:56:35 +0000 https://linuxhint.com/?p=89544

POSIX Inter-process Communication (IPC)

IPC is used for real-time extensions. These message queues are a part of Linux. These calls are used as a standard now but might be a part of contemporary versions. These calls are easy to implement with a much cleaner interface.

POSIX Message Queues in Linux

V message queues in a Linux system are identified using keys that are obtained using ftok calls. These POSIX message queues usually use name strings. In Linux systems, POSIX queues are called strings. These strings are considered to start with / and then have other characters.  Processes that follow and know the name of the queue name with appropriate rights can send or receive messages to and from the queue. This will help in performing important functionalities.

What Are POSIX Message Queue Calls?

POSIX message queues must link with any library that exits for real. Following are a few calls that are used:

librt uses the compiler option -lrt

Call names begin with the mq_prefix

The details of Queue Calls are discussed below:

>> mq_open, mq_close

This function is used to open up a POSIX queue.

Mq_open is a function that is used to call the name of the queue. The next parameter is a flag used to receive the messages. O_WRONLY is used to send messages, and O_RDWR is used to send and receive operations within the queue. Users can use the O_NONBLOCK flag to specify the queue to the non-blocking mode and mq_send and mq_receive to send and receive data in a queue.

Syntax
The syntax for the above queue call is displayed below:

#include <fcntl.h>
/* used to open the files */
#include <sys/stat.h>
/* to determine a file based on the path */
#include <mqueue.h>
/* to include message queue descriptions */
mqd_t mq_open (const character *name, int oflag);
/* to open up and access the queue */
mqd_t mq_open (const character *name, int oflag, mode_t mode,
    struct mq_attribute *attribute);

Mq_Flags: Could be O or non-block

Mq_MaxMsg: Maximum number of messages that can be entered inside the queue

Mq_Msgsize: Maximum number of bytes in a message

Mq_CurMsgs: Currently sent messages within a queue

mq_close calls: To close all of the queue descriptors.

mq_notify

It is a call used to register and unregister arrival notification when a message enters an empty queue.

Syntax

#include <mqueue.h>
/* to include all of the message queue descriptions from the code */
int mq_notify (mqd_t mqdes, const struct sigevent *sevp);
/* to notify the arrival of the message in a queue */

mq_unlink

It is used to remove the queue having queue_name.

Syntax

int mq_unlink(const char *queue_name);
/* To remove the queue having name as queue_name */

mq_getattr, mq_setattr

This function has an attribute structure:

struct mq_attr is used as a message queue for descriptors.

mq_setattr is used for setting the attributes inside a queue.

Syntax

#include <mqueue.h>
int mq_getattribute(mqd_t mqdes, struct mq_attribute *attribute);
int mq_setattribute(mqd_t mqdes, const struct mq_attribute *newattribute,
    struct mq_attribute*oldattr);

Example: Client-Server Communication via POSIX

The following is an example of performing client-server communication via POSIX message queues. In the example, we will have a client file and server file.

We will have two files: the first (server) file is server.c, and the other (client) file is client.c.

Server Code

The image displayed below shows the code that we used for client-server communication. First, we called some libraries to define the strings, variables, and functions. Then, we defined the fcntl function and the name of the queue server. After that, we defined the name of the server queue, followed by its message size and buffer size, to define the size of messages to fit our buffer at a time. Next, we called and described the queues, then we generated the next tokens to see the client response once it was sent to the client. Finally, the confirmation was completed by printing the message from the server end. In the next section, you will see the flags discussed in the earlier section.

We initialized all flags, including mq_flags, mq_maxmsgs, etc. to proceed with storing requests. Then, we applied the condition to the name of the server and stored the messages in the queue buffer. After this, at the time of storage, we ensured that the queues followed a first-come-based priority rule. At the end, the code displays a failure message if there are any errors received from the client-end. Finally, we exited the server to send the request to the client.

Save the server.c file

Client Code

We will now discuss the second file. The image displayed below is the code we used for the client-server communication. The code began by calling standard libraries and defining variable headers. Then, we defined the strings and all types of data. After that, we declared the header of the queue to define the server queue name. Next, we defined the permission queues and message size inside the queue, along with the size of the message buffer (the maximum size that could fit inside the queue).

We will describe the queues and create a new client to receive the messages sent from the end of the server. Then, we will call the flags and initialize them, and call the client-end function. It will exit the function in the case of an error. The value is stored inside the buffer, and a request response is sent to the server. In case of a response, the server will then provide the token, which is printed once the client end has entered the input. In case of an error, it will return the error values, i.e., the client has not been able to send a message to the server. After that, we will exit the client.

Save the client.c file

Executing the Files

We are using a gcc compiler to execute the files. To run the server end file, type the appended command in the terminal window:

$ sudo gcc server.c -lrt

Next, type the following:

$ ./a.out

The output will appear as follows:

Moving on to the client response, type the following:

$ sudo gcc client.c -lrt

Then run the following:

$ ./a.out

The output will appear as follows:

Conclusion

In this article, you learned how to send POSIX Message Queues with C programming, as well as some of its functions. Then, you saw some examples of this process in greater detail.

]]>
Macro in C language https://linuxhint.com/write-macro-c-language/ Sun, 07 Feb 2021 13:00:01 +0000 https://linuxhint.com/?p=89164 A macro in C language is a piece of code which has been assigned a name. When the name is used anywhere in the program, the macro value is replaced before the program’s compilation. In this article, we will see in detail how to write a macro in C language.

Consider the following code:

START

    INTEGER n=5;
   
    PRINT("Value of n is %d",n);

END

The above code is not a valid C code.

But the following code is valid:

//Example1.c
#define START int main(){
#define END }
#define INTEGER int
#define PRINT(A,B) printf(A,B)


START

    INTEGER n=5;
   
    PRINT("Value of n is %d",n);

END

Before compilation, the macro START, INTEGER, PRINT and END has been replaced by their value, and the code becomes a valid C code. We can check using the following command:

gcc –E Example1.c

This command will show after expanding all the macros.

Now we will see different types of macros:

1. Object-like macros:

Syntax:

#define macro_name  macro_value
  • Macro is always starting with #define
  • macro_name is a user-defined name of the macro
  • macro_value is the value of the macro. It may be anything, but one line and the macro body ends with that line’s ends. It does not require semicolon (;) at the end. Space is also considered.

If the macro takes more than one line we can do it as follows:

#define macro_name  macro_value1 \
                    macro_value2 \
                    macro_value3


#define MAX 200

This macro looks like a data object that’s why this type of macro called as an object-like macro.

//Example2.c  
//#include <stdio.h>
#define MAX 200  
     
int main()  
{  
    printf("MAX Value is: %d",MAX);  
    return 0;
}

In Exapmle2.c, MAX is a macro. From the output, we observe that MAX is replaced by its value 200.

2. Function-like macros:

Syntax:

#define macro_name()  macro_value

macro_name is a user-defined name of the macro. Pair of parenthesis has to put after the macro_name. No space is allowed between macro_name and parenthesis. We also can pass arguments in this type of macros.

#define add(x,y) x+y

This macro looks like a function call that’s why this type of macro called a function-like macro.

//Example3.c  
     
#define add(x,y) x+y  
     
int main()  
{  
     
    int a;  
    float b;  
     
    a = add(4,5);  
    b = add(2.5,3.6)  
         
    return 0;
}

In Example3.c, we have seen that unlike C’s function, the macro replace only the code with arguments without calculating it. So, we can pass different data type using the same macro.

If we put a space between the macro name and parenthesis, it works the same as an object-like macro. Below C Example illustrates this.

//Example4.c  
 
#define add (x,y) x+y  
 
int main()  
{  
 
    int a;  
    float b;  
     
    a = add(4,5);  
    b = add(2.5,3.6)
}

In Example4.c, we have seen that the macro add is replaced by (x,y) x+y . Same as an object-like macro.

3. Macro for Token Pasting:
In C language, ## operator is used for token pasting. Using this operator, we can combine two valid tokens into one valid token.
Example:

//Example5.c  
#define MARGE(x,y) x##y  
 
int main()  
{  
 
    int num = MARGE(52,34);  
    return 0;
}

If we try to token pasting that does not generate a valid token, the C compiler gives an error or warning.

//Example6.c  
#define MARGE(x,y) x##y  
 
int main()  
{  
 
    int num = MARGE(52,+);  
    return 0;
}

In Example6.c, we have an error message because, after a combination of two tokens, we get an invalid token ’52+’.

4. Macro for Stringizing:
In C language, # operator is used to converting a macro parameter into a string constant. When a # operator precedes with a macro parameter, the parameter converts to a string literal. Stringizing can be used for object-like and function-like macros.
Example:

//Example7.c  
#define STRINGIZING(x) #x  
 
int main()  
{  
 
    printf(STRINGIZING(Hello World) );  
    return 0;
}

In Example7.c we have got a string “Hello World” using STRINGIZING macro.

Conclusion:

This article has learned about all types of macro-like Object-like macros, Function-like macros, Macro for Token Pasting, Macro for Stringizing and Macro for Stringizing in C language. Now we can use a macro in our C program without any doubt. ]]> POSIX Signals with C Programming https://linuxhint.com/posix-signals-c-programming/ Wed, 03 Feb 2021 18:34:50 +0000 https://linuxhint.com/?p=89025 We may define a signal as an activity that is triggered to alert an operation or thread whenever the time of arrival for a certain significant situation. Whenever a procedure or thread acknowledges a signal, the procedure or thread will halt whatever it is doing and take immediate action. In inter-process coordination, the signal can be effective. In this guide, you will study signal handlers in Linux through the C language.

Standard or Regular Signals:

The header file ‘signal.h’ has signals specified in it as a macro constant. The title of the signal began with “SIG” and is preceded by a brief signal overview. Consequently, any signal does have a distinct numeric value. The program code should use the signal’s name, not several signals. The cause behind it is that the number of signals can vary depending on the system, but the interpretation of names is standard. Below are some regular signals with their functionality defined.

SIGHUP:

This signal will hang-up the processing. The SIGHUP signal is being cast off to indicate user terminal disassociation, likely due to a remote communication being broken or hanging up.

SIGINT:

It will disrupt the process. The SIGINT signal is received whenever the user inputs the INTR key (usually Ctrl + C).

SIGQUIT:

It will stop or exit the processing. The SIGQUIT signal is received whenever the user inputs the QUIT key (usually Ctrl + \).

SIGILL:

It runs when an illicit command has been made. The SIGILL signal is created whenever an effort is being made to perform a junk or privileged command. Whenever the stack overflows and the machine has problems running a signal controller, SIGILL may also be created.

SIGTRAP:

It is called when some trace trap instruction is being executed. The SIGTRAP signal is created by a breakpoint command and another trap command. The debugger uses such a signal.

SIGABRT:

It is called the Abort signal. The SIGABRT signal is created by calling the abort() method. Such a signal is used to point out the inaccuracy observed by the code the aforementioned and recorded by the abort() method call.

SIGFPE:

Exception for floating-points; The SIGFPE signal is produced when a catastrophic mathematical error occurs.

SIGUSR1 and SIGUSR2:

The SIGUSR1 and SIGUSR2 signals could be used the way you like. It is beneficial for easy interprocess interaction to create a signal handler for such signals in the application that gets the signal.

Default Behavior of Signals:

There is standard behavior or action per each signal, and it is possible to adjust the default behavior using the handler function. The automatic SIGKILL and SIGABRT signal behavior could not be modified or neglected.

Term: It will terminate the operation.

Core: A core dump document will be generated, and the operation will be terminated.

Ign: The process would overlook a signal.

Stop: It’ll halt the operation.

Cont: The operation will be sustained from being halted.

Signal Handling:

The process has a preference of behavior for a signal when it is acknowledged. The process may behave like the following:

The signal is automatically dismissed when the defined signal behavior is overlooked.

Using methods like signal or sigaction, the code may register a handler function. It is called catching a signal from a handler.

If a signal is not being treated or neglected, the standard action may occur.

You can define the Signal Handling function as:

 $ Int signal () int signum, void (*funk)(int))

When the processing obtains a signal signum, the signal() method may call the ‘func’ method. Signal() reverts a pointer to the ‘func’ method if it’s prosperous or an exception is returned to errno and -1 instead.

The ‘func’ pointer is capable of having three values:

SIG_DFL: This is a pointer to the standard SIG DFL() method, defined in the header.h document used for getting the signal’s standard behavior.

SIG_IGN: This is a reference to the SIG IGN() ignore method, specified in the header.h document.

User-defined handler method pointer: The user-defined handler method type void(*)(int), implies that the return category is void and that solitary argument is int.

Create a new file ‘signal.c’ and write below signal handler code in it.

Link the signal.c file with gcc.

While running the signal.c file, we have got an endless loop carrying out in the main method. On pressing CTRL+C, it started the handler method, and the main method execution stopped. The main method processing continued after the accomplishment of the handler method. Upon hitting Ctrl+\, the operation quits.

Signal Ignore:

For overlooking the signal, create a file ‘signal.c’ and write underneath code in it.

Tie the ignore.c file with gcc.

Run the signal.c file. Tap CTRL+C, SIGNIT signal is created; nevertheless, the behavior is unnoticed because the handler method is enumerated to SIG_IGN() method.

Reregister Signal Handler:

To re-register the signal handler, create a new file ‘rereg.c’ and inscribe the below code in it:

Associate the rereg.c file with gcc.

Run the rereg.c file. While first time pressing CTRL+C handler method raised, and signal handler re-registered to SIG_DFL. While pressing CTRL+C again, the execution got terminated.

Send Signals Using Raise():

Create a file ‘send.c’ and add the below code. For sending signals to the calling method, the raise() method is used.

Relate the send.c file with gcc.

The process utilizes the raise() method to transmit the SIGUSR1 signal on its own.

Send Signals Using Kill():

Add the below code in ‘raise.c’. Use the kill method() to send signals to the process group.

Link the raise.c file with gcc.

By using the kill() method, the process directs the SIGUSR1 signal to the aforementioned.

Parent-Child Interaction:

To watch parent-child interaction, write the below code in a file.

Bond the comm.c file with gcc.

Fork()/ method generates child, revert zero to the child process, and child ID to parent.

Conclusion:

In this guide, we have seen how to create, handle, send, ignore, re-register and use the signal for inter-process interaction in Linux.

]]>
POSIX Shared Memory with C Programming https://linuxhint.com/posix-shared-memory-c-programming/ Wed, 03 Feb 2021 17:59:39 +0000 https://linuxhint.com/?p=89012 POSIX shared memory is a framework for inter-process communication (IPC) specified in the POSIX specifications. Two (or more) tasks can read from it and write to the shared memory zone while establishing the shared memory. POSIX shared memory does not always enforce copy disbursements, in contrast to other IPC structures (e.g., pipe, socket, etc.), and is desirable for certain programs.

POSIX Shared Memory Calls

The POSIX shared memory functions focused on the UNIX concept that the object must be a document when performing input/output activities on an entity. Therefore, because you recite and inscribe to a mutual POSIX memory entity, the latter must be considered as a document. A memory-mapped document is a POSIX shared memory entity. To use the shm_open system call function beneath /dev/shm, separate shared memory documents are generated. There are only two dedicated shared memory system calls from POSIX, shm_open, and shm_unlink, which are closely related to opening and unlinking file system calls. The ftruncate, mmap, and munmap framework calls for documents are used to perform other tasks on POSIX shared memory. It is necessary to connect a program that uses POSIX shared memory calls to -lrt.

Programs using POSIX shared memory calls must go through the following steps:

Using shm_open(), form a shared memory object. The document descriptor can be reverted if the formation of the object is successful.

With ftruncate(), the size of the object will be fixed.

With map() and MAP_SHARED, delineate this object into the present address space.

Read/write the shared memory.

Via munmap(), un-delineate the shared memory.

Use close() to shut the object.

Through shm_unlink(), delete the object in the shared memory.

shm_open()

As described above, shm_open() is used to generate a new shared memory object. It makes the object accessible to the calling procedure using the reverted descriptor. The following is the definition of this function call:

>> Int shm_open( const char *name, int oflag, mode_t mode);

The first parameter is the shared memory object’s name. It is a null-terminated string of the /name type, with the stipulation that no other character can be a slash other than its first character. Oflag is a small veil created with several of the preceding flags by OR-ing, whether via O_RDONLY or O_RDWR. The parameters described indicate that its shared-memory object must be formed (O_CREAT) when it does not already exist and also the object is available for reading and writing (O_RDWR). The very last argument sets the directory approvals for the shared-memory object.

shm_unlink()

Shm_unlink() eliminates the POSIX shared memory entity that was formerly developed. The integer document descriptor for the shared-memory object is returned via an effective call to shm_open(). As defined beneath the shm_open(), the parameter name is the title of the shared memory entity. The following is the definition of the shm_unlink() function:

>> Int shm_unlink( const char *name);

ftruncate()

Upon setting the object, the ftruncate() method is cast off to set up the entity size in bytes. The function definition is as follows:

>> Int ftruncate( int fd, off_t length);

When constructing a shared POSIX memory, it is indeed zero bytes in size capacity. You may render the POSIX shared memory entity with bytes of size length via ftruncate. Ftruncate yields zero on execution. Ftruncate outputs -1 in case of a failure and errno is set to trigger the error.

mmap()

Eventually, a memory-mapped document with the shared-memory entity is set via the mmap() method. Then, it yields a memory-mapped document pointer that is cast off to reach the shared-memory entity. The following is the definition of the mmap() function:

>> Void *mmap ( void *addr, size_t length, int prot, int flags, int fd, off_t offset);

In this, ‘addr’ is the address to which it will be mapped. The ‘length’ is the range of the shared memory entity. The values for prot may differ, but we will use the PROT READ | PROT WRITE. There are several flags, but MAP SHARED is essential for shared memory. Now, ‘fd’ is a document descriptor that was obtained earlier. Offset is the point where the mapping begins in the shared memory entity; the 0 offset value can also be used. On completion, mmap() yields the pointer to the mapping position of the shared memory entity.

munmap()

At the position directed by addr and getting size, length, munmap unmaps the shared memory item. Munmap yields 0 upon completion and -1 in the situation of inaccuracy, in which case errno is assigned to trigger the error.

>> Void munmap ( void *addr, size_t length);

Example: Sender and Receiver

Let us take the example of the sender and the receiver. The sender will create a new shared-memory object with the name /shmem-example and inscribe three numerals into the shared memory through it. Now, the receiver may expose the shared-memory object and recite the three numerals from the memory. We will create three files with the names protocol.h, sender.c, and receiver.c.

$ touch protocol.h

$ touch sender.c

$ touch receiver.c

Next, we will add the below source code to the files ‘protocol.h,’ ‘sender.c,’ and ‘receiver.c.’ Now, we will save all and close them.

Now we will be compiling and joining the above code using the keyword –lrt separately for the sender.c and receiver.c file. Here is the command to do so:

$ gcc –o sender sender.c –lrt

$ gcc –o receiver receiver.c –lrt

Now, we will run the sender code using the following command. The output is given below.

$ ./sender

Running the sender code, the shared memory object has been generated and can be found beneath /dev/shm using the command below:

$ ls –l /dev/shm | grep shmem-example

When we run the receiver code, we will obtain the output below:

$ ./receiver

Whenever the function gm_unlink() is called using the file ‘receiver.c,’ the object /dev/shm/shmem-example will be detached. In this case, you will obtain no object on output, as shown below.

$ ls –l /dev/shm/shmem-example

Conclusion

In this article, you learned how to use POSIX Shared Memory with C programming in Ubuntu 20.04, including every function call used to establish shared memory. I hope that this article helped you to improve your programming knowledge and covered every doubt you have on this subject.

]]>
POSIX Thread with C Programming https://linuxhint.com/posix-thread-c-programming/ Wed, 03 Feb 2021 17:27:42 +0000 https://linuxhint.com/?p=88999 A thread is a small instance running within a process. Threads combine to create a process, and they have some properties of the process; therefore, they are considered lightweight processes. Thread is not independent, just like a process. Rather they work together to compile and create a process. Still, just like a process, a thread also has its own PC (Program Counter) and a particular register set along with stack space.

POSIX Thread:

In Linux platforms, the C and C++ languages pthread standard API for all kinds of thread related functions. It is also known as a POSIX thread that allows users to create many threads for simultaneous processes to flow. It is best used in multi-core systems or processors to implement threads on the kernel to achieve the system.

Implementation:

It is necessary to include this pthread.h header file in the script initially. This will help in using the functions of the pthreads library. To execute the c file, the following commands

$ cc -pthread file.c

OR

$ cc -lpthread file.c

The functions that are defined in the pthreads library can include:

pthread_create:

It is used to create a new thread

Parameters of pthread_create:

It has the following parameters:

thread: This acts as a pointer to an unsigned integer value. It returns the thread id of the thread that is formed.

attributes: This parameter acts as a pointer to a structure. It is used to define attributes of a thread that can be the policy of scheduling, and stack address, etc.

start_routine: This parameter is a pointer to a subroutine implemented by the thread.

argument: This parameter is a pointer to void with different arguments to the function pre-defined at the start of the argument

Syntax:

>> int pthread_create

(pthread_t * thread, const pthread_attributes_t * attr, void * (*start_routine)(void *), void *argument);

pthread_exit:

It is used to terminate or end a thread

Parameters of pthread_exit:

The method used at the end of the method/process accepts a parameter retval that is a compulsory indicator to an integer. It stores the status of the thread such that the thread terminates. It must be a global variable. This will allow the next thread in line to join the thread if it is available.

Syntax:

>> void pthread_exit(void *retval);

pthread_join:

This is a function used at the time of wait for the termination of the thread.

Parameters for pthread_join:

The parameter used here are:

thread_id: It is the ID of the thread for which the thread in line waits.

thread_return: It is the parameter that acts as a pointer to the particular location where we have defined the exit status.

Syntax:

>> int pthread_join(pthread_t thread_identification, void **thread_return);

pthread_self:

This is a method used to get the id of the thread currently in line.

Syntax:

>> pthread_t pthread_self(void);

pthread_equal:

This method is used to compare in case two threads are equivalent or not. If two threads are alike, then the function will return a value other than zero in response.

Syntax:

>> int pthread_equal(pthread_t thread1, pthread_t thread2);

pthread_cancel:

This method is used to send a request for cancellation

Parameter for pthread_cancel:

The parameter used is mandatory to be entered to cancel the request.

Syntax:

>> int pthread_cancel(pthread_t threadName);

pthread_detach:

This is the method that is used to separate a thread. It does not need any thread to join on the termination. All of the resources running in the thread are released as soon as the thread is detached.

Parameter of pthread_detachr:

It is the parameter that accepts the mandatory parameter thread id. It is a must to be detached.

Syntax:

>> int pthread_detach(pthread_t thread);

Sample code:

Here is an example code to show the implementation of the above-described function. We used a gcc compiler to compile these functions.

// Program to show the thread functions

#include<stdio.h>

#include<pthread.h>

#include<stdlib.h>

// Calling the POSIX thread, a must-have in UNIX/LINUX systems

pthread_t tid[2];

void*Function(void *arg)

{

    unsigned long i = 0;

    pthread_t id = pthread_self();

    if(pthread_equal(id,tid[0]))

// Condition for threads being equal

    {

        printf("\n First thread is being processed\n");

    }

    else

    {

        printf("\n Second thread is being processed \n");

    }

// Threads being processed.

    for(i=0; i<(0x255);i++);

    return NULL;

}

int main(void)

{

    int i = 0;

    int error;

// Creating a new thread

    while(i < 2)

    {

        error = pthread_create(&(tid[i]), NULL, &Function, NULL);

        if (error != 0)

            printf("\n Not been able to create the thread :[%s]", strerror(error));

        else

            printf("\n Thread has been created successfully\n");

// Thread created successfully

        i++;

    }

    sleep(5);

    return 0;

}

The code is written in a text editor; you can use any editor based on your choice. Then save it in your favorite location.

The file is saved in the computer system and then is accessed. The file saved by us was named test.c. To access it, type the following command in the terminal window:

$ sudo gcc test.c -lpthread

Next, to execute the output, type the following command:

$ ./a.out

Expected Output:

The output we got in response to the previous code is shown below:

Conclusion:

The tutorial covered the basic process of thread creation and discussed all of the commonly used methods in its creation. Thread is an instance of a process. We then walked users through the famous parameters used by each process along with the syntaxes so that they can make use of them in their computer programs. Here we also shared an example code as a sample to better understand the idea of creating a C program in POSIX. The compiler we used was gcc in the Linux system. Users can opt for any other compiler as well based on their preference.

]]>
Posix Open Function with C Programming https://linuxhint.com/posix-open-function-c-programming/ Tue, 02 Feb 2021 23:21:27 +0000 https://linuxhint.com/?p=88705 The concept of file handling is extensively used in all programming languages. Specifically for C and C++, you will find a vast literature on the information regarding the concept of file handling. Whenever you want to access or modify a file in C or C++, you must open it first, either for reading or writing. The task of opening a file is accomplished with the help of the Posix Open function.

This function contains a set of parameters that are passed along with this function to open a specified file. We will discuss these parameters in the next heading of our article. However, the main goal of this article is to educate you about the usage of the Posix Open function in Linux Mint 20. In this article, learn how the Open function works with C programming.

Parameters of the Posix Open Function

The Posix Open function contains two parameters that are further divided into various types. The first parameter is known as the Path, which refers to the location of the file that you wish to open. If you are creating your C code to open a file in the same directory in which the file to be opened resides, then you just have to write the name of the file and omit its path. However, if the file to be opened resides in any other directory, then you must specify its complete path as a parameter to the Open function followed by the forward-slash (“/”).

The second parameter of the Posix Open function is known as the Flag, which refers to the options with which you can open a file. These options are read-only, write-only, read and write, create file, and prevent file creation. The corresponding flags of these operations are O_RDONLY, O_WRONLY, O_RDWR, O_CREAT, and O_EXCL respectively. You can either use one of these flags at a time or you can combine more than one flag at once, depending on your requirements, separated by the “|” symbol. You will begin to understand these flags more clearly after reading the example given below.

Example: Using the Posix Open Function in Linux Mint 20

To provide an example of using the Posix Open function with C programming in Linux Mint 20, we have created a program that attempts to open a file. If that file already exists, then this function will simply open it; otherwise, the function will create a file with the specified name. Now, we will take a look at all the stages of execution of this program, beginning with its creation.

Step 1: Create Sample Program to Test Posix Open Function

Here, we have created a document in the Home directory of our Linux Mint 20 system and named it OpenFunction.c. After creating this document, we will open it and type the code shown in the image below in that file.

In the code shown in the image above, we have created an integer variable, named fd, which refers to the File Descriptor. This variable will be assigned the return value of the Open function. The value of this variable will be “3” if the Open function executes successfully. Otherwise, its value will be “-1.” In the parameters of the Open function, we have provided a filename, i.e., “NewFile.txt.” This file did not exist in our system before, which means that our Open function will create this file.

Also, we have specified via the flags of the Open function that if the file already exists, then the file should be opened in the read-only mode; whereas if it does not exist, then the Open function will simply create a file with the specified name. We have also specified that if the value of the fd variable is less than zero, then the function will also print the error that occurred while opening the specified file. Finally, you can save your code by pressing Ctrl + S.

Step 2: Compile Sample Program

After writing the sample program, we will launch the terminal to compile it with the following command:

$ gcc OpenFunction.c –o OpenFunction

Here, OpenFunction.c refers to the sample program file that we wish to compile, whereas OpenFunction after the “-o” flag refers to the object file that will be created after compilation.

If the compilation of our sample program is carried out successfully, then we will not see any error messages in the terminal after running the program, as shown in the image below:

Step 3: Run Sample Program

Finally, after compiling our sample program, we can run it in Linux Mint 20 by issuing the following command:

$ ./OpenFunction

Here, “OpenFunction” refers to the same object file that was created following the compilation of our sample program.

You can see in the output of our sample program in the image below that the value of our File Descriptor variable, i.e., fd, is “3.” This output means that the code has been executed successfully. In other words, a file named “NewFile.txt” has been created successfully, since the file did not exist previously in our system. If you want, you can even go and check it out in your Home directory to verify whether the file has been created.

Conclusion

Today’s tutorial showed you how to use the Posix Open function with C programming in Linux Mint 20. Hopefully, the provided example will be sufficient to emphasize the importance of this function. No matter what the reason for opening a file, you still have to use this function to gain access to a file. Without this function, you will not be able to access any files. Therefore, you must learn the usage of this function before performing file handling in C and C++.

]]>
POSIX Read Function in C Programing https://linuxhint.com/posix-read-functioning-in-c-programming/ Sun, 31 Jan 2021 02:30:53 +0000 https://linuxhint.com/?p=88180 In traditional POSIX compatible operating systems, to get information from a document contained in a file system, a program used the read system call. A document descriptor that is usually accessed from a prior call to open is defined by the file. This read system call reads out the information in bytes and the integer of which the caller specifies from the document, and then saves it in a buffer provided by the calling mechanism.

Function Definition

Before defining the read function in your code, you have to include some required packages.

#include <unistd.h>

Here is how you define the POSIX read function:

>> ssize_t pread(int fildes, void *buf, size_t nbyte, off_t offset);
>> ssize_t read(int fd, void *buf, size_t nbytes);

Three parameter arguments can be taken from the read method call:

int fd: The file descriptor of the file from where the information is to be read. We could either be using a file descriptor acquired via an open system call, or we could just use 0, 1, or 2 referring to typical input, regular output, or regular error, respectively.

Void *buf: The buffer or character array in which the read data should be saved and kept.

Size_t nbyte: The number of bytes that needed to be read from the document before truncating. All information can be stored in the buffer if the information to be read is shorter than nbytes.

Description

The read() method tries to read ‘nbyte’ bytes into the buffer cache referred to by ‘buf’ from either the file connected with the open document descriptor ‘Fildes’ or ‘fd’. It does not define the nature of several simultaneous reads on the same stream, FIFO, or terminal unit.

On documents that enable the reading, the reading process begins at the offset of the document, and the offset is increased by the number of bytes read. If the document offset is at or beyond the file’s edge, there are no bytes read, and read() yields none.

When the count is 0, read() will recognize the errors mentioned below. If there are no mistakes, or if read() is not accounted for with Errors, a read() yields zero with a count of 0 and therefore has no other repercussions.

If the count is higher than SSIZE_MAX, as per POSIX.1, then the outcome is determined by the implementation.

Return Value

The numeral of bytes ‘read’ and ‘pread’ reverted upon achievement must be a non-negative integer while zero points to the end of the file. The document position is progressed by this number, or else, to signify an error, the methods return -1 and assign ‘errno’. When this figure is less than the number of bytes requested, it is not a mistake byte. It could be possible that fewer bytes are available for now.

Errors

The pread and read function will be unsuccessful if these errors occur:

EAGAIN:

The document or file descriptor ‘fd’ belongs to a non-socket file that has been labeled as non-blocking (O NONBLOCK) and will block the reading.

EWOULDBLOCK:

The descriptor ‘fd’ belongs to a socket that has been labeled as non-blocking (O_NONBLOCK) and will block the reading.

EBADF:

The ‘fd’ may not be a usable descriptor, or it may not be open for reading.

EFAULT:

This happens when your ‘buf’ is outside your reachable address space.

EINTR:

Before the reading of information data, the call may have broken up by a signal.

EINVAL:

This error occurs when your ‘fd’ descriptor is involved in an object, which is not appropriate for reading, or the document was untied with the O_DIRECT flag, and one or the other address stated in ‘buf’, the value indicated in ‘count’, or the document offset is not appropriately associated.

EINVAL:

The descriptor ‘fd’ may have been formed using a call to timerfd_create(2), and the incorrect size buffer has been given to read.

EIO:

It is an input/output error. It occurs when the background process group attempts to read from its regulatory terminal, and one or the other is overlooking or blocking SIGTTIN, or its process group is bereaved. Another reason for this error could be low-level input/output error meanwhile reading from a hard disk or tape. Another potential cause of EIO on networked data files is the removal of advisory locking on the file descriptor and the failure of that lock.

EISDIR:

The file descriptor ‘fd’ belongs to a directory.

Notes:

Many other errors may also occur, contingent on the object linked to descriptor ‘fd’. Both size_t and ssize_t forms are unmarked and marked numerical data types defined by POSIX.1. On Linux, at most 0x7ffff000 (2,147,479,552) bytes can be transmitted by reading function (and equivalent system calls), returning the number of bytes originally transmitted (on both 32-bit and 64-bit platforms). With NFS filesystems, just the first moment the timestamp is changed by reading tiny streams of information, subsequent calls wouldn’t do so. It is triggered by caching of client-side attributes since, although not all, NFS clients quit updating to the server via st_atime (last file access time) and client-side reads fulfilled from the buffer of the client would not trigger changes to st-atime on the server as no server-side readings are available. By removing client-side attribute caching, UNIX metadata may be accessed, but this would significantly increase the load on the server and affect productivity in most cases.

Example 01:

Here is a C program to demonstrate the read function call on the Linux System. Write the below-command as it is in a new file. Add libraries, and in the main function, initialize a descriptor and size. The descriptor is opening the file, and size is used to read file data.

The output for the above-code would be as shown in the below image.

Example 02:

Another example to illustrate the working of the read function is given below.

Create another file and write down the code below as it is in it. Here are two descriptors, fd1 & fd2, that both have their own open table file access. So for foobar.txt, every descriptor does have its file location. The very first byte of foobar.txt is translated from fd2, and the result is c = f, not c = o.

Conclusion

We have read the POSIX read function in C programming efficiently. Hopefully, there are no doubts left.

]]>
POSIX Socket with C Programming https://linuxhint.com/posix-socket-with-c-programming/ Thu, 28 Jan 2021 15:29:27 +0000 https://linuxhint.com/?p=87966

A POSIX Socket or simply a Socket is defined as a communication endpoint. For example, if two parties, A and B, intend to communicate with each other, then it will be required that both of these parties establish a connection between their respective endpoints. A socket provides the communicating parties with a gateway through which the messages travel. If we talk in terms of the client and server, then the job of the server-side socket will be to listen to the incoming connections, whereas the client-side socket will be responsible for connecting to the server-side socket. This article is intended to make the concept of POSIX socket with C programming much clearer.

Example of Using Posix Socket with C Programming in Linux Mint 20

The example presented to you in this section will demonstrate an interaction between a client and a server. The client and the server are the two main entities of the client/server model in the world of computing. In our example, both the client and the server will be sending and receiving messages to and from each other while making use of the POSIX Socket with C programming in Linux Mint 20. For bringing clarity in the understanding of the code, we have separated the client-side code and the server-side code and will be explaining both of them to you separately below.

The Server-Side Code

For the server-side code, we have simply created an empty document in the Home Directory of our Linux Mint 20 system and named it server.c. In that empty document, you need to write the code snippets shown in the three images below:

The code shown in the images above might seem lengthy, however, let us try to understand it in an extremely easy manner. First of all, we have created a socket and attached it with the desired port number, which in our case is 8080. Then we have written a listen function, which is there to look for all the incoming connections from the clients. Basically, the client manages to connect to the server just because of the presence of this listen function. And once this connection is established, the server is all set to send and receive data to and from the client.

The read and send functions serve the purposes of receiving and sending messages to the clients, respectively. We have already defined a default message in our code that we intend to send our client, and that is “Hello from server”. After sending this message to the client, it will be displayed on the client’s side, whereas a message saying “Hello message sent” will be displayed on the server’s side. This is all about our server-side code.

The Client-Side Code

Now, for the client-side code, again, we have created an empty document in the Home Directory of our Linux Mint 20 system and named it client.c. In that empty document, you need to write the code snippets shown in the two images below:

In the client-side code shown in the images above, we have created a socket in the very same manner as we did for the server-side code. Then, there is a connect function that will attempt to make a connection with the server through the specified port. And once this connection is accepted by the server, the client and server will be all set to send and receive messages to and from each other.

Again, just like the server-side code, the send and read functions are there to send and receive messages from the server, respectively. Also, we have mentioned a default message that we want to send to the server, and that is “Hello from client”. After sending this message to the server, this message will be displayed on the server’s side, whereas a message saying “Hello message sent” will be displayed on the client’s side. And this brings us to the end of the explanation of our client-side code.

Compiling and Running the Client and Server-Side Codes

Obviously, we will be saving both our client-side and server-side files after writing these programs then we will be all set to compile and run these codes. Hence, we will be able to visualize the interaction between our newly created client and server. To achieve this objective, we have to launch two different terminals since we are supposed to run two separate programs. One terminal will be dedicated to running the server-side code, and the other one for the client-side code.

So, for compiling our server-side code, we will execute the following command in the first terminal:

$ gcc server.c –o server

After running this command, if there will be no errors in your server-side code, then nothing will be displayed on the terminal, which will be an indication of a successful compilation.

In the very same manner, we will compile the client-side code with the command shown below by running it in the second terminal:

$ gcc client.c –o client

Once both of the codes are compiled, we will run them one by one. However, we must run the server-side code first since it is supposed to listen to the connection requests. The server-side code can be run with the following command:

$ ./server

After running the server-side code, we can run the client-side code with the command shown below:

$ ./client

Once both the client and server will be up and running, you will witness the outputs shown in the following images on both terminals:

Conclusion

Hopefully, after going through the example shared with you in this article, you will be able to use the POSIX Sockets efficiently for sending and receiving data between a client and server. This example is just a basic demonstration of the Posix sockets with C programming, however, you can even make these programs more complex as per your requirements.

]]>
POSIX Semaphores with C Programming https://linuxhint.com/posix-semaphores-with-c-programming/ Thu, 28 Jan 2021 15:15:29 +0000 https://linuxhint.com/?p=87956

POSIX refers to the Portable Interface of the OS, which is an IEEE standard, developed to assist portability of different applications. POSIX is an effort to build a common standardized version of UNIX through a collaboration of vendors. It would make porting apps among hardware platforms easier if they are effective. Hewlett-Packard is integrating POSIX into its licensed MPE/iX OS version 5.0 and HP/UXX version 10.0, respectively (its UNIX).

The POSIX standard has much more than ten parts, however, two are easily obtainable. POSIX.1 describes C programming interfaces (i.e., a system call library) for files, procedures, and I/O terminals. The C POSIX package library for POSIX platforms is a framework of the C standard library. This is established at the very same time as standard ANSI C. To make POSIX compliant with standard C, several attempts have been made. POSIX provides additional features to those implemented in standard C.

POSIX Semaphores

A semaphore is a data structure often used for synchronizing the processes and assisting threads without their interaction with one another to operate together. The interface for semaphores is specified by the POSIX standard. It is not part of Pthreads. However, most UNIXes that support Pthreads even provide semaphores. In Unix-like frameworks, like Linux, semaphores are merged with message queues and common memory underneath the Interprocess Communication (IPC) services. The older framework V semaphores and the modern POSIX semaphores become two types of semaphores. POSIX Semaphore calling is so much easier than System V Semaphore calls. Although, System V semaphores are easier to obtain, especially on earlier Unix-like platforms. There is a need to connect programs using POSIX semaphores to the Pthread library. We’ll take a look at the POSIX semaphores in this article.

Why POSIX Semaphores?

There is a big issue around threads, which is “race condition”. It is a circumstance in which two threads seek to obtain and alter the same information, thereby making it conflicting. To avoid a race condition, we have been using semaphores for a very long time.

Semaphores are available in 2 kinds:

Binary Semaphore:

It is also recognized as a mutex lock. It would only have two possible values, 0 and 1. The value will be initialized as 1. It’s being used to enforce numerous processes to solve the serious section issue.

Counting Semaphore:

Its size can vary across an unrestricted domain. It’s being used to have authority over access to numerous-instance resources.

The Linux POSIX framework has its integrated Semaphore repository. To use it, we must:

  • Add semaphore.h
  • Pile up the code by connecting with -lpthread -lrt.

Almost all POSIX Semaphore methods and forms are prototyped or specified in ‘Semaphore.h’. We will be using the Semaphore to describe an entity or object as:

>> sem_t sem_name;

Here are different functions we would be using in POSIX Semaphore.

Sem_init

To initialize a semaphore, you have to use the sem_init method. In this function, sem corresponds to an initialized semaphore object. Pshared is a banner or flag that specifies whether the semaphore can be shared with a forked() procedure or not. Shared semaphores are not presently braced by LinuxThreads. The argument value is the starting value at which the semaphore is fixed to.

>> int sem_init(sem_t *sem, int pshared, unsigned int value);

Sem_wait

We will be using the sem-wait method to hold/lock a semaphore or make it wait. If the semaphore has been provided with a negative value, then the call cycle will be automatically blocked. Whenever any other thread calls sem_post, one of the already clogged processes awakes.

>> int sem_wait(sem_t *sem);

Sem_post

We will be using the sem_post method to increase the value of a semaphore. Upon calling, sem_post will increment the value, and one of the already clogged or waiting processes awakes.

>> int sem_post(sem_t *sem);

Sem_getvalue

If you want to know about the value of a semaphore, you have to use the below sem_getvalue  function. It will obtain the present value of the semaphore and be placed in the valp-pointed destination.

>> Int sem_getvalue(sem_t *sem, int *valp);

Sem_destroy

You should be using the sem_destroy method if you want to destroy the semaphore. If the demise of the semaphore is to proceed, no thread will be waiting in the semaphore.

>> Int sem_destroy(sem_t *sem);

Install the GCC Utility

To compile the POSIX Semaphore C code, you must have the gcc utility installed in your Linux system. For this purpose, open your command terminal and try the below command.

$ sudo apt-get install gcc

Affirm your action by hitting Y.

Implementation of POSIX Semaphore with C programming in Ubuntu

At the very start, you have to create a new file with a .cpp extension on Ubuntu 20.04 system. For this, you have to navigate towards your Home Directory and create a new empty file named new.cpp. You can also create it using the touch command in your command terminal.

You can see that the new.cpp file has been created in the Home Directory.


After the creation of the .cpp file, open it as a Text Editor in your Linux system and write the below code in this file as it is. After that, save and close it.

Execute the POSIX Semaphore C Program In Ubuntu 20.04

Open your terminal In Ubuntu 20.04 and execute the below gcc command followed by the filename.

$ gcc filename.c –lpthread –lrt

There are 2 threads formed, one is formed after 2 seconds of the other. After receiving the bolt, the very first thread sleeps for 4 seconds. So, after it has been called, the second thread wouldn’t join directly, and this will appear 4-2=2 seconds after it has been called. Here is the output:

If we had not used semaphore, according to context switching, the result might have been as observes:

Conclusion

In this guide, a detailed overview of the use of POSIXSemaphore with C programming in Ubuntu 20 has been given. By merely using the POSIX or Pthread library throughout certain C code, the POSIX Semaphore can be quite easily used to prevent race conditions during coding.

]]>
Posix Mutex with C Programming https://linuxhint.com/posix-mutex-with-c-programming/ Thu, 28 Jan 2021 03:38:42 +0000 https://linuxhint.com/?p=87999 Today’s article will be focused on the usage of Posix Mutex with C programming in Linux Mint 20. However, before heading on to our main example, we would first like to clear out a few terminologies, so you can easily understand the example scenario that we will be sharing with you. In operating systems, the concept of threading is used extensively. Threads are basically sub-processes that are delegated with different tasks. You can consider the following example to understand the working of threads.

Suppose there is a main thread A, whose job is to calculate the sum of the variables w and y where w=x+1, and y=z+2. The values of the variables x and z are to be fetched by the user. In this scenario, we can create two threads, B and C. The job of thread B will be to take the value of the variable x from the user, increment it by 1, and save it in the variable w. The job of thread C will be to take the value of the variable z from the user, increment it by 2, and then save it in variable y. Finally, both of these threads will handover these results to the main thread A, which will then calculate their sum and display the final result.

If we would not have created any threads in this scenario, then all the tasks would have been performed by the main thread A in a much larger time. In this way, threads can efficiently perform your calculations without any unnecessary delays. However, there is a very major concern with the usage of threads, which is known as the “race condition”. It is a situation in which two threads try to access and modify the very same data, hence leaving it inconsistent. As a programmer, our goal should be to avoid race conditions in the most graceful manner.

The most commonly employed solution for avoiding race conditions is the use of Mutex. Mutex stands for mutual exclusion, and it basically provides us with a locking mechanism that prevents the access and modification of the critical data by more than one user at a time. In this way, data consistency is ensured. Posix is basically a library that presents us with different built-in functions that make the implementation of threads and Mutex much easier. With the following example, we will try to learn the usage of Posix Mutex with C programming in Linux Mint 20.

Example of Using Posix Mutex with C Programming in Linux Mint 20

We will perform the following three steps for walking you through the usage of Posix Mutex with C programming in Linux Mint 20.

Step #1: Creating a Program Demonstrating the Usage of Posix Mutex with C Programming in Linux Mint 20

First of all, we will create a .cpp file on our Linux Mint 20 system. We will simply go to our Home folder, create an empty document, and name it Mutex.cpp. Once our .cpp file is created, we will open it with the text editor. After that, we will type the code shown in the images below to our .cpp file:

The code shown in the two images above created two different threads. The first thread corresponds to Job #1, whereas the second thread corresponds to Job #2. Then we have created a sample function named “Mutex Function”. In this function, we are first locking the Mutex lock variable, and it will only be unlocked once thread #1 finishes Job #1. Similarly, the Mutex lock variable will again be locked by thread #2 until it finishes Job #2. This “Mutex Function” is called by the “main” function.

Step #2: Compiling the C Program in Linux Mint 20

After saving the .cpp file, we will now compile it through the Linux Mint 20 terminal with the following command:

$ gcc –o Mutex Mutex.cpp –pthread

Here, “Mutex”, after the “-o” flag, refers to the name of the object file that will be created, whereas “Mutex.cpp” is the name of the original .cpp file. The “-pthread” flag is necessary to compile this program because this program is written while using the “pthread” library. If you omit this flag, your program will not be compiled and will render some errors. The successful compilation of our .cpp file will not produce any messages on the terminal, as shown in the image below:

Step #3: Running the C Program in Linux Mint 20

Once the object file named “Mutex” has been created, we can run it using the following command:

$ ./Mutex

In the output of our Mutex.cpp program, you will notice that first Job 1 has started, which means that thread #1 has acquired the Mutex lock. After that, Job 1 finishes after some time. Then, Job 2 starts, which means that thread #2 has acquired the Mutex lock. It will only be unlocked once Job 2 finish.

Conclusion

This article provided an in-depth explanation of the usage of Posix Mutex with C programming in Linux Mint 20. The Mutex can be used very effectively to avoid the race conditions while programming by simply including the Posix or pthread library in our C code. This will not only ensure data consistency but will also make the processing much more efficient.

The best thing about using the Posix library in Linux is that we do not even need to install any specialized software, packages, or compiler for it. The C code can simply be written in any default text editor on Linux and can be compiled and run with the default gcc or g++ compilers. This proves to be an added layer of ease and convenience in the usage of Posix Mutex with C programming in Linux Mint 20.

]]>
2D Array https://linuxhint.com/2d-array-in-c-program/ Thu, 26 Nov 2020 14:37:15 +0000 https://linuxhint.com/?p=78234 A Two-dimensional (2D) array is an array of one dimensional (1D) arrays. The 1D array sizes are equal. The 2D array is also called a matrix with rows and columns.

Let’s see the following example:

These 3 1D arrays can be represented as a 2D array as follows:

Let’s see another example:

These 3 1D arrays cannot be representing as a 2D array because the sizes of the arrays are different.

Declaration of 2D array

data-type array-name[ROW][COL]

  • Data-type is the data type of the array elements.
  • Array-name is the name of the array.
  • Two subscripts represent the number of rows and columns of the array. The total number of elements of the array will be ROW*COL.

int a[2][3];

Using the above C code, we can declare an integer array, a of size 2*3 (2 Rows and 3 Columns).

char b[3][2];

Using the above C code, we can declare a character array, b of size 2*3 (3 Rows and 2 Columns).

Initialization of 2D array

We can initialize during declaration in following ways:

  1. int a[3][2] = {1,2,3,4,5,6};
  2. int a[][2] = {1,2,3,4,5,6};
  3. int a[3][2] = {{1, 2},{3, 4},{5, 6}};
  4. int a[][2] = {{1, 2},{3, 4},{5, 6}};

Note that in 2 and 4 we have not mentioned the 1st subscript. The C compiler automatically calculates number of rows from the number of elements. But the 2nd subscript must be specified. Following initializations are invalid:

  1. int a[3][] = {1,2,3,4,5,6};
  2. int a[][] = {1,2,3,4,5,6};
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
//Example1.c  
#include  
#define ROW 3  
#define COL 2  
 
int main()  
{  
    int i,j;  
    int a[ROW][COL] = {  
        {1,2},  
        {3,4},  
        {5,6}  
    };  
     
    printf("Row wise Elements of the array a are :\n");  
     
    for(i=0;i<ROW;i++)  
    {  
        printf("Row %d:",i);  
        for(j=0;j<COL;j++)  
        {  
            printf(" %d",a[i][j]);  
        }  
        printf("\n");  
    }    
     
    printf("\n\nColumn wise Elements of the array a are :\n");  
     
    for(i=0;i<COL;i++)  
    {  
        printf("Column %d:",i);  
        for(j=0;j<ROW;j++)  
        {  
            printf(" %d",a[j][i]);  
        }  
        printf("\n");  
    }  
     
    return 0;  
}

In Example1.c, we have declared an integer array of size 3*2 and initialized. To access array elements, we use two for loop.

To access row-wise, the outer loop is for rows, and the inner loop is for columns.

To access column-wise, the outer loop is for columns, and the inner loop is for rows.

Note that when we declare a 2D array, we use a[2][3], which means 2 rows and 3 columns. Array indexing starts from 0. To access the 2nd row and 3rd column, we have to use the notation a[1][2].

Memory mapping of a 2D array

The logical view of an array a[3][2] may be as follows:

Computer memory is a 1D sequence of bytes. In C language, a 2D array store in the memory in row-major order. Some other programming languages (e.g., FORTRAN), it stores in column-major order in the memory.

Pointer Arithmetic of a 2D array

To understand the pointer arithmetic of the 2D array, first, have a look at the 1D array.

Consider a 1D array:

In 1D array, a is a constant, and its value is the address of the 0th location of the array a[5]. Value of a+1 is the address of the 1st location of the array a[5].  a+i is the address of the ith location of the array.

If we increment a by 1, it is incremented by the size of the data type.

a[1] is equivalent to *(a+1)

a[2] is equivalent to *(a+2)

a[i] is equivalent to *(a+i)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//Example2.c  
#include  
#define ROW 3  
#define COL 2  
 
int main()  
{  
    int a[5]={10,20,30,40,50};  
 
    printf("sizeof(int): %ld\n\n",sizeof(int));  
 
    printf("a: %p\n",a);  
    printf("a+1: %p\n",a+1);  
    printf("a+2: %p\n\n",a+2);  
 
    printf("a[1]: %d,  *(a+1): %d\n",a[1],*(a+1));  
    printf("a[2]: %d,  *(a+2): %d\n",a[1],*(a+1));  
    printf("a[3]: %d,  *(a+3): %d\n",a[1],*(a+1));  
     
    return 0;  
}

In Example2.c, the memory address is showing in hexadecimal. The difference between a and a+1 is 4, which is the size of an integer in bytes.

Now, consider a 2D array:

b is a pointer of type: int[ ][4] or int(*)[4]

int[ ][4] is a row of 4 integer. If we increment b by 1, it is incremented by the size of the row.

b is the address of the 0th row.

b+1 is the address of the 1st row.

b+i is the address of ith row.

The size of a row is: ( Number of column * sizeof(data-type)) bytes

Size of a row of an integer array b[3][4] is: 4 * sizeof(int) = 4 * 4 = 16 bytes

A row of a 2D array may be viewed as a 1D array. b is the address of the 0th row. So, we get the following

  • *b+1 is the address of the 1st element of the 0th
  • *b+j is the address of the jth element of the 0th
  • *(b+i) is the address of the 0th element of the ith
  • *(b+i)+j is the address of the jth element of the ith
  • b[0][0] is equivalent to **b
  • b[0][1] is equivalent to *(*b+1)
  • b[1][0] is equivalent to *(*(b+1))
  • b[1][1] is equivalent to *(*(b+1)+1)
  • b[i][j] is equivalent to *(*(b+i)+j)

Address of b[i][j]: b + sizeof(data-type) * ( Number of column * i + j)

Consider a 2D array: int b[3][4]

Address of b[2][1] is : b + sizeof(int) * (4*2 + 1)

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
//Example3.c  
#include  
#define ROW 3  
#define COL 4  
 
int main()  
{  
    int i,j;  
    int b[ROW][COL] = {  
        {10,20,30,40},  
        {50,60,70,80},  
        {90,100,110,120}  
    };  
     
    printf("sizeof(int): %ld\n",sizeof(int));  
    printf("Size of a row: %ld\n",COL*sizeof(int));  
    printf("b: %p\n",b);  
    printf("b+1: %p\n",b+1);  
    printf("b+2: %p\n",b+2);  
    printf("*b: %p\n",*b);  
    printf("*b+1: %p\n",*b+1);  
    printf("*b+2: %p\n",*b+2);  
    printf("b[0][0]: %d    **b: %d\n",b[0][0],**b);  
    printf("b[0][1]: %d    *(*b+1): %d\n",b[0][1],*(*b+1));  
    printf("b[0][2]: %d    *(*b+2): %d\n",b[0][2],*(*b+2));  
    printf("b[1][0]: %d    *(*(b+1)): %d\n",b[1][0],*(*(b+1)));  
    printf("b[1][1]: %d    *(*(b+1)+1): %d\n",b[1][1],*(*(b+1)+1));  
     
    return 0;  
}

In Example3.c, we have seen that size of a row is 16 in decimal notation. The difference between b+1 and b is 10 in hexadecimal. 10 in hexadecimal is equivalent to 16 in decimal.

Conclusion

So, in this article, we have learned about

  1. Declaration of 2D array
  2. Initialization of 2D array
  3. Memory mapping of 2D array
  4. Pointer Arithmetic of 2D array

Now we can use 2D array in our C program without any doubt,

References

Credit for some ideas in this work were inspired by the course, Pointers and 2-D Arrays, by Palash Dey Department of Computer Science & Engg. Indian Institute of Technology Kharagpur

]]>
How Memset Function is Used https://linuxhint.com/memset_function/ Sun, 15 Nov 2020 03:47:47 +0000 https://linuxhint.com/?p=76575

In C, the memset() function is used to set a one-byte value to a memory block byte by byte. This function is useful for initialization of a memory block byte by byte by a particular value. In this article, we will see in detail how this function can be used. So, let’s get started.

Header File:

1
string.h

Syntax:

1
void *memset(void *str, int ch, size_t n)

This function sets the first bytes of the memory block pointed by str by ch.

Arguments:

The function takes 3 arguments:

  1. str: This is the pointer of the memory location where the memory will be set. This is a void pointer, so we can set any type of memory block, but the memory will be set byte by byte.
  2. ch: This is the value that is to be copied to the memory block. This is an integer value, but it is converted to an unsigned character before copied.
  3. n: This is the number of bytes in the memory block which is set.

Return values:

memset() returns the first address of the memory block from where it starts to set the value.

Examples:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//Example1.c
#include<stdio.h>
#include<string.h>

int main()  
{  
    char str[30] = "ABCD EFGH";  
     
    printf("Before memset => %s",str);  
     
    memset(str,'x',3);  
     
    printf("\nAfter memset => %s\n",str);  
     
    return 0;  
}


In Example1.c, we have declared one character array of size 30. Then we have initialized it with the string “ABCD EFGH.” In the memset function, we have passed 3 arguments str, ‘x’ and 3. So, the memory block pointed by str will be reset the first 3 characters by ‘x.’ After memset, when we print the memory, we will get “xxxD EFGH.”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//Example2.c
#include<stdio.h>
#include<string.h>

int main()  
{  
    char str[30] = "ABCD EFGH";  
     
    printf("Before memset => %s",str);  
     
    memset(str+4,'x',3);  
     
    printf("\nAfter memset => %s\n",str);  
     
    return 0;  
}


In Example2.c, we have passed str+4 to memset function. So, it reset the memory after the 4th location of str.  After memset, when we print the memory, we will get “ABCDxxxGH.”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Example3.c
#include<stdio.h>
#include<string.h>

int main()  
{  
    int arr[5],i;  
     
    memset(arr,10,5*sizeof(arr[0]));  
     
    printf("\narr Elements => \n");  
     
    for(i=0;i<5;i++)  
        printf("%d\t",arr[i]);  
     
    printf("\n");
    return 0;
}


In Example3.c, we have declared an integer array of size 5 and trying to initialize it by 10. But from the output, we have seen that the array is not initialized by 10; instead, we have got the value “168430090”. This is because the integer value is greater than one byte and the memset function converts the value to an unsigned character before copied. Now, we will see how we will get the value “168430090”.


The binary representation of 10 is 00000000 00000000 00000000 00001010.

When integer converted to unsigned char, the lower 1 byte is considered. So, when 10 is converted to unsigned char, it’s a binary representation is 00001010.

memset() function sets the memory location byte by byte. So, a total of 4 bytes will be: 00001010 00001010 00001010 00001010.

The decimal value of the binary representation of 4 bytes is 168430090.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Example4.c
#include<stdio.h>
#include<string.h>

int main()  
{  
    int arr[5],i;  
     
    memset(arr,0,5*sizeof(arr[0]));  
     
    printf("\narr Elements => \n");  
     
    for(i=0;i<5;i++)  
        printf("%d\t",arr[i]);  
     
    printf("\n");
    return 0;
}


In Example4.c, we have initialized the integer array by 0. All bits of the binary representation of 0 is 0. So the array is initialized by 0.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Example5.c
#include<stdio.h>
#include<string.h>

int main()  
{  
    int arr[5],i;  
     
    memset(arr,-1,5*sizeof(arr[0]));  
     
    printf("\narr Elements => \n");  
     
    for(i=0;i<5;i++)  
        printf("%d\t",arr[i]);  
     
     printf("\n");
     return 0;
 
}


In Example5.c, we have initialized the integer array by 0. All bits of the binary representation of -1 is 1. So the array is initialized by -1.

Conclusion:

In this article, we have seen using the memset function how we can initialize or set the value of a memory block efficiently. We can set any character and 0 or -1 as an integer value to a memory block. Memset function is faster to set a large chunk of contiguous memory in comparison with simply setting the location using a loop.

]]>
Static in C Programming https://linuxhint.com/static_c/ Tue, 27 Oct 2020 23:13:14 +0000 https://linuxhint.com/?p=74316 In this tutorial, we will explain the static keyword by applying it in variables and functions. Static is a keyword used in C programming, and it can be applied by using the following syntax:

static {data type} {variable name}

Static local variables

When a variable in a function is static, the variable preserves its value between function calls.

//Example1.c  
 
#include<stdio.h>  
 
int fun1()  
{  

    int count=0;  
    count++;  
    return count;  
}  
 
int fun2()  
{  
    static int count=0;  
    count++;  
    return count;  
}  
 
int main()  
{  
    printf("fun1 1st call returns : %d\n",fun1());  
    printf("fun1 2nd call returns : %d\n\n",fun1());  
 
    printf("fun2 1st call returns : %d\n",fun2());  
    printf("fun2 2nd call returns : %d\n",fun2());  
 
    return 0;  
}


In Example 1.c, we have two functions: fun1() and fun2(). In fun1(), we declare one variable (count) and initialize it to 0. Then, we increment the count variable and return the resulting value. Using main(), we call fun1() twice, and each time, a value of 1 is returned because the count variable is cleared when the call to fun1() is completed. In fun2() we declared the count variable as a static variable. Therefore, its value is preserved. Using main(), we call fun2() twice: the first time, a value of 1 is returned, and the second time, a value of 2 is returned.

Static global variables

A static global variable behaves in the same way as other global variables, but it cannot be accessed from another C program.

Static functions

In C, functions are global by default. However, if we declare a static function, then the function is local and cannot be accessed from another C program.

Initialization of static variables

If a static variable is not explicitly initialized, then it is initialized as 0.

//Example2.c  
 
#include<stdio.h>  
 
int main()  
{  
    static int i;  
     
    printf("Value of i : %d\n",i);  
 
    return 0;  
}


In Example2.c, we declared a static variable i that is not initialized. However, because the variable is static, it is automatically initialized to 0.

It is important to note that a static variable must be initialized by a constant literal; we cannot use a function’s return value to initialize a static variable.

//Example3.c  
 
#include<stdio.h>  
 
int fun1()  
{  
    return 5;  
}  
 
int main()  
{  
    static int i = fun1();  
    printf("Value of  i : %d\n",i);  
    return 0;  
}


In Example3.c, we try to initialize a static variable by using the return value of fun1(). However, as you can see, an error is returned when the code is compiled.

Summary

The lifetime of a static variable and the lifetime of the program are equal.

If a static variable is not initialized, then it will take on a default value of 0.

Neither a global static variable nor a static function is accessible from a program other than the one in which it was defined.

]]>
rand() Function in C Language https://linuxhint.com/rand-function-in-c-language/ Thu, 22 Oct 2020 03:27:13 +0000 https://linuxhint.com/?p=72619 In the C language, the rand() function is used for Pseudo Number Generator(PRNG). The random numbers generated by the rand() function are not truly random. It is a sequence that repeats periodically, but the period is so large that we can ignore it. The rand() function works by remembering a seed value that is used to compute the next random number and the next new seed. In this article, we are going to discuss in detail how random numbers can be generated using the rand() function. So, let’s get started!

Header File:

stdlib.h

Syntax:

int rand (void)

Return values:

This function returns the next pseudo-random number in the series. The range value of the number series is between 0 and RAND_MAX. RAND_MAX is a macro defined in stdlib.h header file, whose value is the maximum value, which can return by rand() function. The value of RAND_MAX is greater but not less than 32767 depending on the C libraries.

//Example1.c  
     
#include<stdio.h>  
#include<stdlib.h>  
     
int main()  
{  
     
    int i;  
     
    printf("10 Random Numbers =>\n");      
         
    for(i=0;i<10;i++)  
    {  
        printf("%d ",rand());  
    }  
     
    printf("\n");  
    return 0;
}


In Example1.c, we call the rand() function in each iteration of for loop and print the return value of the function. The value sequence of the rand() function is the same each time we run the program. By default, the seed of the rand function is set to 1.

We can set the seed for the rand function using the srand() function. The seed can be set only once, and before the first time rand() function call.

srand() function:

Header File:

stdlib.h

Syntax:

int srand (unsigned int seed)

Arguments:

This function takes 1 argument

seed: An integer value used as a seed for a new series of pseudo-random numbers.

Return values:

None

//Example2.c  
 
#include<stdio.h>  
#include<stdlib.h>  
#include<time.h>  
 
int main()  
{  
 
    int i;  
 
    srand(time(0));  
 
    printf("10 Random Numbers =>\n");      
     
    for(i=0;i<10;i++)  
    {  
        printf("%d ",rand());  
    }  
 
    printf("\n");  
    return 0;  
}


In Example2.c, we have used the srand() function to set the initial seed of the random number sequence generated by rand() function. Each time the program is run, a different sequence is generated. In srand(), time(0) function (declared in time.h header file) is used as a seed. This time(0) function returns the number of seconds elapsed since the epoch (00:00:00, January 1, 1970). This still may produce the same sequences if you run the program in the same second.

//Example3.c  
 
#include<stdio.h>  
#include<stdlib.h>  
#include<time.h>  
 
int main()  
{  
 
    int i;  
 
    srand(time(0));  
 
    printf("10 Random Numbers between 1 and 10=>\n");      
     
    for(i=0;i<10;i++)  
    {  
        printf("%d ",(rand() %10) + 1);  
    }  
 
    printf("\n");  
    return 0;  
}


In Example3.c we have seen how random numbers can be generated between 1 and 10.

//Example4.c  
 
#include<stdio.h>  
#include<stdlib.h>  
#include<time.h>  
 
int main()  
{  
 
    int i,max,min;  
 
    printf("Enter Min value => ");  
    scanf("%d",&min);  
    printf("Enter Max value => ");  
    scanf("%d",&max);  
     
    if(min>max)  
    {  
        printf("Min value is greater than max value\n");  
        return 0;  
    }  
 
    srand(time(0));  
     
 
    printf("10 Random Numbers between %d and %d=>\n",min,max);    
     
    for(i=0;i<10;i++)  
    {  
        printf("%d ",(rand() % (max - min +1)) + min);  
    }  
 
    printf("\n");  
    return 0;  
}


In Example4.c we have taken the range from the user and generated a random number within this range. The formula is: rand() % (max – min +1)) + min

//Example5.c  
 
#include<stdio.h>  
#include<stdlib.h>  
#include<time.h>  
 
int main()  
{  
 
    int i;  
 
    srand(time(0));  
 
    printf("10 Random Numbers between 0.0 and 1.0=>\n");  
     
    for(i=0;i<10;i++)  
   {  
        printf("%f ",((float)rand() /RAND_MAX));  
    }  
 
    printf("\n");  
    return 0;  
}


In Example5.c, we have seen how we can generate random numbers between float 0.0 and 1.0 The formula is: (float)rand() /RAND_MAX)

//Example6.c  
 
#include<stdio.h>  
#include<stdlib.h>  
#include<time.h>  
 
int main()  
{  
 
    int i;  
    float max,min;  
 
    printf("Enter Min value => ");  
    scanf("%f",&min);  
    printf("Enter Max value => ");  
    scanf("%f",&max);  
 
    if(min>max)  
    {  
        printf("Min value is greater than max value\n");  
        return 0;  
    }  
 
    srand(time(0));  
 
    printf("10 Random Numbers between %f and %f =>\n",min,max);    
     
    for(i=0;i<10;i++)  
    {  
        printf("%f ",min + ((float)rand() /(RAND_MAX/(max - min))));  
    }  
 
    printf("\n");  
    return 0;  
}


In Example6.c, we have taken the range from the user and generated a random number within this range (both inclusive). The formula is: min + ((float)rand() /(RAND_MAX/(max – min)))

Conclusion:

In this article, we have learned how random numbers can be generated using the rand() and srand() function. There are no guarantees about the quality of the random numbers generated by the rand function, but it is good enough for casual use. ]]> How to use memcpy function in C language? https://linuxhint.com/memcpy_function_c_programming/ Thu, 08 Oct 2020 10:44:01 +0000 https://linuxhint.com/?p=70317 In the C language memcpy() function is used to copy a block of memory from one location to another. In this article, we are going to discuss in detail how the memcpy() function is used. So, let’s get started.

Header File:

string.h

Syntax:

void * mempcpy (void *dest, const void *src, size_t size)

Arguments:

The function takes 3 arguments:

  1. dest :
  2. This is a starting pointer of a memory block where the memory block pointed by src (2nd argument) will be copied. The pointer is declared as void, so any type of memory block can be copied.

  3. src :
  4. This is a starting pointer of the source memory block from where the memory block will be copied. The pointer is declared as void, so any type of memory block can be copied.

  5. size :
  6. This is the size of the memory block in bytes.

The value of the two pointer dest and src should be in such a way that two memory blocks do not overlap. The size of memory blocks of source and destination must be at least of size (3rd argument) bytes to avoid overlapping situations. If the two memory blocks are overlapped then the behavior of the memcpy() function is undefined. When there is a possibility of overlapping, you can use the memmove() library function where overlapping is well defined. memmove() function is slower compared to memcpy() function.

Due to the value of size, if the source or destination is accessed beyond their buffer length then the behavior of the memcpy() function is undefined.

The memcpy() function does not check to terminate ‘\0’ character.

Return values:

This function returns the value of destination address dest. As the value of dest is already available so, it need not to store in any variable.

Examples:

   //Example1.c  
     
   #include<stdio.h>  
   #include<string.h>  
     
   int main()  
   {  
       char src[] = "Hello";  
       char dest[13];  
       
      memcpy(dest,src,6);      
       
      printf("dest after first memcpy() => %s\n",dest);  
   
      memcpy(dest+sizeof(src)-1," world!",8);  
   
      printf("dest after second memcpy() => %s\n",dest);  
   
      return 0;  
  }

In Example1.c we have declared two-character array src and dest. The size of the src is 6 and the dest is 13. First, we copied 6 characters ‘H’, ‘e’, ‘l’, ‘l’, ‘o’, ‘\0’ from src to dest ( Line 11 ). In the second memcpy() function copied 8 characters ‘ ’, ‘w’, ‘o’, ‘r’, ‘l’, ‘d’, ‘!’, ‘\0’ to the dest after 5 characters ( Line 15 ). Pictorially we can represent this as follows:

//Example2.c  
 
#include<stdio.h>  
#include<string.h>  
 
int main()  
{  
    typedef struct student  
    {  
        char *name;  
        int id;  
        int age;  
    }std;  
 
    std student1; // Declare student1 of type std  
    std student2; // Declare student2 of type std  
     
    // Assigning the value of sudent1  
    student1.name = "Bamdev Ghosh";  
    student1.id = 1105;  
    student1.age = 30;  
 
    printf("Student1:\n\tName : %s\n\tid : %d\n\tage : %d\n",student1.name,
    student1.id,student1.age);  
     
    // Copy student1 to student2      
    memcpy(&student2, &student1, sizeof(student1));  
     
    printf("\n\nAfter memcpy:");  
    printf("\n\nStudent2:\n\tName : %s\n\tid : %d\n\tage : %d\n",
    student2.name,student2.id,student2.age);  
 
    return 0;  
}

In Example2.c we have declared two structure student1 and student2 (Line 15 and 16). First, we initialize student1 (Line 19, 20, 21). After that, we use memcpy to copy data from student1 to student2.

Conclusion:

In this article, we have learned how to use the memcpy function. We have seen that this function can be used for any type of memory block but this function has some limitations. So, you have to use this function carefully. ]]> String Length in C Language https://linuxhint.com/string_length_c_language/ Fri, 02 Oct 2020 17:45:59 +0000 https://linuxhint.com/?p=69761 A string in C language is an array of characters that is terminated with a null character (\0). The string length is the number of characters in a string. In the string length ‘\0,’ a character is not counted.

In the example shown above, the length of the string str is 6.

In this tutorial, first, we will show how to use a user defined function to calculate length of a string, and then we will show you a built-in library function strlen(). We also show you the uses of the sizeof operator for string literals.

String Length Using User Defined Function

You can write a user defined function which returns the number of characters in a string.

//Example1.c  
#include<stdio.h>  
 
int stringLength(char *str)  
{  
    int i=0;  
     
    while(str[i] != '\0') i++;  
     
    return i;  
}  
 
int main()  
{  
    char str[30]= "STRING";  
     
    printf("Length of the string str is => %d\n",stringLength(str));  
         
    return 0;  
}

Here, we iterate the while loop from i = 0 until we do not encounter the ‘\0’ character. The value of i is increased by 1 in each iteration of the while loop. When the loop ends, the value of i is the length of the string.

String Length Using Built-In Library Function

The built-in library function strlen() can also be used to determine string length.

strlen() function:

Header file:

string.h

Syntax:

size_t strlen (const char *str)

Argument: This function takes an argument of the type pointer to char.

Return value: This function returns the length of the string str. Note that size_t is just an alias of an unsigned integer.

//Example2.c  
#include<stdio.h>  
#include<string.h>  
 
int main()  
{  
    char str1[30]="STRING ARRAY";  
    char *str2;  
    char *str3;  
     
    str2 = str1;  
    str3 = "STRING POINTER";  
     
    printf("Length of the string str1 is => %ld\n",strlen(str1));  
    printf("Length of the string str2 is => %ld\n",strlen(str2));  
    printf("Length of the string str3 is => %ld\n",strlen(str3));  
    printf("Length of the string "STRING LITERALS" is => %ld\n",strlen("STRING LITERALS"));  
         
    return 0;  
}

Here, we pass string array, string pointer, and string literal to the strlen function, and the function returns the length of the string.

String Length Using sizeof Operator

We also can use the sizeof operator for string length (only for string literal). But, we have to subtract 1 from the value returned by this operator, because it also counts the’\0’ character. For array and pointer, the sizeof operator returns the allocated size of the array and the pointer, respectively.

//Example3.c  
#include<stdio.h>  
 
int main()  
{    
    char str1[30] = "STRING";  
    char *str2 =str1;  
     
    printf("Length of "STRING" is => %d\n",(sizeof("STRING") - 1));  
    printf("Allocated size of the str1 array is => %d\n",sizeof(str1));  
    printf("Size of the str2 pointer is => %d\n",sizeof(str2));  
         
    return 0;  
}

Here, in Line no 9, we pass the string literal “STRING” and get the size, including the ‘\0’ character. So, we subtract 1 and get the actual size of the string.

When we pass an array to the sizeof operator, it returns the allocated size of the array, which is 30, and when passing a character pointer, it returns the size of the pointer.

Conclusion

So, in this tutorial, we have shown you how string length can be calculated in various ways. You can use in your code whichever method is best suited for you.

]]>
Setting Decimal Precision in C Language https://linuxhint.com/setting_decimal_precision_c_-language/ Fri, 25 Sep 2020 02:53:21 +0000 https://linuxhint.com/?p=69090

This article will show you how to set decimal precision in C programming language. First, we will define precision, and then, we will look into multiple examples to show how to set decimal precision in C programming.

Decimal Precision in C

The integer type variable is normally used to hold the whole number and float type variable to hold the real numbers with fractional parts, for example, 2.449561 or -1.0587. Precision determines the accuracy of the real numbers and is denoted by the dot (.) symbol. The Exactness or Accuracy of real numbers is indicated by the number of digits after the decimal point. So, precision means the number of digits mentioned after the decimal point in the float number. For example, the number 2.449561 has precision six, and -1.058 has precision three.

32-bit single-precision floating-point number

As per IEEE-754 single-precision floating point representation, there are a total of 32 bits to store the real number. Of the 32 bits, the most significant bit is used as a sign bit, the following 8 bits are used as an exponent, and the following 23 bits are used as a fraction.64-bit single-precision floating-point number

In the case of IEEE-754 double-precision floating point representation, there are a total of 64 bits to store the real number. Of the 64 bits, the most significant bit is used as a sign bit, the following 11 bits are used as an exponent, and the following 52 bits are used as a fraction.

However, when printing the real numbers, it is necessary to specify the precision (in other words, accuracy) of the real number. If the precision is not specified, the default precision will be considered, i.e., six decimal digits after the decimal point. In the following examples, we will show you how to specify precision when printing floating-point numbers in the C programming language.

Examples

Now that you have a basic understanding of precision, let us look at a couple of examples:

    1. Default precision for float
    2. Default precision for double
    3. Set precision for float
    4. Set precision for double

Example 1: Default Precision for Float

This example shows that the default precision is set to six digits after the decimal point. We have initialized a float variable with the value 2.7 and printed it without explicitly specifying the precision.

In this case, the default precision setting will ensure that six digits after the decimal point are printed.

#include <stdio.h>

int main()
{
    float f = 2.7;

    printf("\nValue of f     =  %f \n", f);
    printf("Size of float    =  %ld \n", sizeof(float));
   
    return 0;
}

vbox - default precision

Example 2: Default Precision for Double

In this example, you will see that the default precision is set to six digits after the decimal point for double type variables. We have initialized a double variable, i.e., d, with the value 2.7 and printed it without specifying the precision. In this case, the default precision setting will ensure that six digits after the decimal point are printed.

#include <stdio.h>

int main()
{
    double d = 2.7;

    printf("\nValue of d      =  %lf \n", d);
    printf("Size of double  =  %ld \n", sizeof(double));
   
    return 0;
}

Default Precision for Double

Example 3: Set Precision for Float

Now, we will show you how to set precision for float values. We have initialized a float variable, i.e., f, with the value 2.7, and printed it with various precision settings. When we mention “%0.4f” in the printf statement, this indicates that we are interested in printing four digits after the decimal point.

#include <stdio.h>

int main()
{
    float f = 2.7;

    /* set precision for float variable */
    printf("\nValue of f (precision  = 0.1)     =  %0.1f \n", f);
    printf("\nValue of f (precision  = 0.2)     =  %0.2f \n", f);
    printf("\nValue of f (precision  = 0.3)     =  %0.3f \n", f);
    printf("\nValue of f (precision  = 0.4)     =  %0.4f \n", f);
   
    printf("\nValue of f (precision  = 0.22)    =  %0.22f \n", f);
    printf("\nValue of f (precision  = 0.23)    =  %0.23f \n", f);
    printf("\nValue of f (precision  = 0.24)    =  %0.24f \n", f);
    printf("\nValue of f (precision  = 0.25)    =  %0.25f \n", f);
    printf("\nValue of f (precision  = 0.40)    =  %0.40f \n", f);
   
    printf("Size of float  =  %ld \n", sizeof(float));
   
    return 0;
}

Set Precision for Float

Example 4: Set Precision for Double

In this example, we will see how to set precision for double values. We have initialized a double variable, i.e., d, with the value 2.7 and printed it with various precision settings. When we mention “%0.52f” in the printf statement, this indicates that we are interested in printing 52 digits after the decimal point.

#include <stdio.h>

int main()
{
    float f = 2.7;

    /* set precision for float variable */
    printf("\nValue of f (precision  = 0.1)     =  %0.1f \n", f);
    printf("\nValue of f (precision  = 0.2)     =  %0.2f \n", f);
    printf("\nValue of f (precision  = 0.3)     =  %0.3f \n", f);
    printf("\nValue of f (precision  = 0.4)     =  %0.4f \n", f);
   
    printf("\nValue of f (precision  = 0.22)    =  %0.22f \n", f);
    printf("\nValue of f (precision  = 0.23)    =  %0.23f \n", f);
    printf("\nValue of f (precision  = 0.24)    =  %0.24f \n", f);
    printf("\nValue of f (precision  = 0.25)    =  %0.25f \n", f);
    printf("\nValue of f (precision  = 0.40)    =  %0.40f \n", f);
   
    printf("Size of float  =  %ld \n", sizeof(float));
   
    return 0;
}

Set Precision for Double

Conclusion

Precision is a very important factor for representing a real number with adequate accuracy. The c programming language provides the mechanism to control the accuracy or exactness of a real number. However, we cannot change the actual precision of the real number. For example, the fraction part of a 32-bit single-precision floating-point number is represented by 23 bits, and this is fixed; we cannot change this for a particular system. We can only decide how much accuracy we want by setting the desired precision of the real number. If we need more accuracy, we can always use the 64-bit double-precision floating-point number.

]]>
How to use Strcpy() in C language? https://linuxhint.com/strcpy_c_language/ Fri, 18 Sep 2020 18:37:52 +0000 https://linuxhint.com/?p=68617 In this article, we are going to learn about the strcpy() function in the C programming language. The strcpy() function is a very popular standard library function to perform the string copy operation in the C programming language. There are several standard header files in C programming language to perform standard operations. The “string.h” is one of such header files, which provides several standard library functions to perform string operations. The “strcpy()” function is one of the library functions provided by “string.h”.

Syntax:

char* strcpy (char* destination_location, const char* source_string);

Understanding strcpy():

The sole purpose of the strcpy() function is to copy a string from source to destination. Now, lets us look at the above syntax of strcpy() function. The strcpy() function is capable of accepting two parameters –

  • char * destination
  • const char * source

The source is a constant here to ensure that the strcpy() function cannot change the source string. The strcpy() function copies all the characters (including the NULL character at the end of the string) from the source string to the destination. Once the copy operation is complete from source to destination, the strcpy() function returns the address of the destination back to the caller function.

The important point to notice here is, the strcpy() function does not append the source string with the destination string. It rather replaces the content of the destination with the content of the source string.

Also, the strcpy() function does not perform any checks to ensure that the size of the destination is more than the source string, it is completely the responsibility of the programmer.

Examples:

Now, we will see several examples to understand the strcpy() function:

  1. strcpy() – Normal Operation (example1.c)
  2. strcpy() – Case-1 (example2.c)
  3. strcpy() – Case-2 (example3.c)
  4. strcpy() – Case-3 (example4.c)
  5. strcpy() – User Defined Version (example5.c)
  6. strcpy() – User Defined Version Optimized (example6.c)

strcpy() – Normal Operation (example1.c):

This example program shows how to perform a normal string copy operation using the strcpy() function in the C programming language. Please note that the length of the destination string is 30 (char destination_str[30]; ), which is greater than the length of the source string (length is 18 including the NULL character) so that the destination can accommodate all the characters from the source string.

#include <stdio.h>
#include <string.h>
   
int main()
{
    char source_str[] = "www.linuxhint.com";
    char destination_str[30];          
   
    printf("Before calling strcpy() function : \n\n");
    printf("\tSource String       = %s\n", source_str);
    printf("\tDestination String  = %s\n\n", destination_str);
   
    strcpy(destination_str, source_str);  
   
    printf("After executing strcpy() function : \n\n");
    printf("\tSource String       = %s\n", source_str);
    printf("\tDestination String  = %s\n\n", destination_str);
   
    return 0;
}

strcpy() – Case-1 (example2.c):

The intent of this example program is to clearly explain what happens when the length of the destination string is less than the length of the source string. In such cases, the destination location will not have enough spaces/bytes to accommodate all the characters (including NULL character) from the source string. Two things, you should always keep in mind:

  1. The strcpy() function will not check if the destination has enough space.
  2. This could be dangerous in embedded software because the strcpy() will replace the memory area beyond the destination’s boundary.

Let us look at the example program. We have declared source_str and initialized it to “www.linuxhint.com”, which will take 18 bytes in memory to store, including the Null character at the end of the string. Then, we have declared another character array i.e. destination_str with the size of only 5. So, the destination_str cannot hold the source string with a total size of 18 bytes.

But, still, we are calling the strcpy() function to copy the source string to destination string. From the below output, we can see the strcpy() did not complain at all. In this case, the strcpy() function will start copying the character from the source string (until it finds the NULL character in the source string) to the destination address (even though destination boundary exceeds). That means the strcpy() function does not do any boundary checking for destination array. Eventually, the strcpy() function will overwrite the memory addresses which are not allocated to the destination array. This is why the strcpy() function will end up overwriting the memory locations which might be allocated to a different variable.

In this example, we can see from the below output, that the strcpy() function overwrites the source string itself. Programmers should always be careful with such behavior.

#include <stdio.h>
#include <string.h>
   
int main()
{
    char source_str[] = "www.linuxhint.com";
    char destination_str[5];
   
    printf("Before calling strcpy() function : \n\n");
    printf("\tSource String       = %s\n", source_str);
    printf("\tDestination String  = %s\n\n", destination_str);
   
    strcpy(destination_str, source_str);  
   
    printf("After executing strcpy() function : \n\n");
    printf("\tSource String       = %s\n", source_str);
    printf("\tDestination String  = %s\n\n", destination_str);
   
    //printf("Source Address      = %u (0x%x)\n", &source_str[0], &source_str[0]);
    //printf("Destination Address = %u (0x%x)\n", &destination_str[0], &destination_str[0]);
   
    return 0;
}

strcpy() – Case-2 (example3.c):

This program illustrates the situation when the destination string size is greater than the source string size and destination string is already initialized with some value. In this example, we have initialized:

  • source_str to “www.linuxhint.com” [size = 17+1 = 18]
  • destination_str to “I_AM_A_DESTINATION_STRING” [size = 25+1 = 26]

The strcpy() function will copy all the 17 characters and the NULL character from the source string to the destination string. But, it will not replace/change the remaining bytes (Byte 19 to 26, one based) in the destination array. We have used for loop to iterate over the destination array and print the whole array to prove that the bytes-19 to 26 are unchanged in the destination array. That is why we see the last output as:

www.linuxhint.com_STRING”.

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


/* This program illustrates the situation when :
   
    destination string size > source string size
   
    and we execute strcpy() function to copy the
    source string to destination.
   
    Note: The destination string size should always
    be greater than or equal to the source string.
*/

int main()
{
    char source_str[] = "www.linuxhint.com";
    char destination_str[26] = "I_AM_A_DESTINATION_STRING";
   
    printf("Before calling strcpy() function : \n\n");
    printf("\tSource String       = %s\n", source_str);
    printf("\tDestination String  = %s\n\n", destination_str);
   
    strcpy(destination_str, source_str);  
   
    printf("After executing strcpy() function : \n\n");
    printf("\tSource String       = %s\n", source_str);
    printf("\tDestination String  = %s\n\n", destination_str);

   
    /* print destination string using for loop*/   
    printf("Print the destination string char by char : \n\n");
    printf("\tDestination String  = ");
   
    for(int i=0; i<25;i++)
    {
        printf("%c", destination_str[i]);
    }
    printf("\n\n");
   
    return 0;
}

strcpy() – Case-3 (example4.c):

We have considered this program as an example to show that we should never call strcpy() with a string literal as the destination. This will cause undefined behavior and eventually, the program will crash.

#include <stdio.h>
#include <string.h>
   
int main()
{
    char source_str[] = "www.linuxhint.com";
   
    printf("Before calling strcpy() function : \n\n");
    printf("\tSource String       = %s\n", source_str);
   
    /* Never call strcpy() with string literal as destination.
       The program will crash.
    */

    strcpy("destination_str", source_str);  
   
    printf("After executing strcpy() function : \n\n");
    printf("\tSource String       = %s\n", source_str);
   
    return 0;
}

strcpy() – User Defined Version (example5.c):

In this example program, we have shown how to write a user-defined version of strcpy() function.

#include <stdio.h>
char * strcpy_user_defined(char *dest, const char * src);

/* User defined version of strcpy() function */
char * strcpy_user_defined(char *dest, const char * src)
{
    char * dest_backup = dest;
   
    while(*src != '\0')    /* Iterate until '\0' is found.*/
    {
        *dest = *src;     /* Copy source char to destination */
        src++;            /* Increment source pointer */
        dest++;         /* Increment destination pointer */
    }
   
    *dest = '\0';         /* Insert '\0' in destination explicitly*/
   
    return dest_backup;
}
   
int main()
{
    char source_str[] = "www.linuxhint.com";
    char destination_str[30];
   
    printf("Before calling user defined string copy function : \n\n");
    printf("\tSource String       = %s\n", source_str);
    printf("\tDestination String  = %s\n\n", destination_str);
   
    /* Calling user defined string copy function */
    strcpy_user_defined(destination_str, source_str);  
   
    printf("After executing user defined string copy function : \n\n");
    printf("\tSource String       = %s\n", source_str);
    printf("\tDestination String  = %s\n\n", destination_str);
   
    return 0;
}

strcpy() – User Defined Version Optimized (example6.c):

Now, in this example program, we are going to optimize the user-defined version of strcpy().

#include <stdio.h>
char * strcpy_user_defined(char *dest, const char * src);


/* Optimized version of user defined strcpy() function */
char * strcpy_user_defined(char *dest, const char * src)
{  
    char * dest_backup = dest;
   
    while(*dest++ = *src++)
    ;
   
    return dest_backup;
}
   
int main()
{
    char source_str[] = "www.linuxhint.com";
    char destination_str[30];
   
    printf("Before calling user defined string copy function : \n\n");
    printf("\tSource String       = %s\n", source_str);
    printf("\tDestination String  = %s\n\n", destination_str);
   
    /* Calling user defined string copy function */
    strcpy_user_defined(destination_str, source_str);  
   
    printf("After executing user defined string copy function : \n\n");
    printf("\tSource String       = %s\n", source_str);
    printf("\tDestination String  = %s\n\n", destination_str);
   
    return 0;
}

Conclusion:

The strcpy() function is a very popular and handy library function to perform the string copy operation in the C programming language. This is mainly used to copy the string from one location to another location. However, we want to reiterate the fact that the strcpy() function does not do the boundary checking for the destination array, which could lead to a serious software bug if ignored. It is always the responsibility of the programmer to make sure the destination array has enough space to hold all the characters from source string including the NULL character.

]]>
How to Use isalpha() in C Language https://linuxhint.com/use_isalpha_c_language/ Fri, 18 Sep 2020 11:06:17 +0000 https://linuxhint.com/?p=68555 There are several standard library header files in the C programming language used to perform various standard operations. The “ctype.h” is one such header file, and the “isalpha()” function is one of the library functions provided by “ctype.h.” The isalpha() library function is used to identify whether a character is an alphabet. In this article, you will learn about the isalpha() library function in C language.

Prototype of isalpha()

This is the prototype for the function in C programming language:

int isalpha (int character_input);

Understanding isalpha()

The isalpha() function is a library function provided by “ctype.h.” This function checks whether a character is an alphabet character. If the function detects that the input character is an alphabet character (‘A’ to ‘Z’ or ‘a’ to ‘z’), it returns a non-zero integer value. But if the input character is not an alphabet character, then the function returns zero.

If you look closely at the function prototype mentioned above, the function takes one argument of the integer type. However, when we call the isaplha() function, we pass a character (‘A’ to ‘Z’ or ‘a’ to ‘z’). The value of the character is converted into an integer value. In C language, a character is stored in the memory as the corresponding ASCII value. Each alphabet has a corresponding ASCII value. For example, the ASCII value for “A” is 65, “b” is 98, etc.

Note: ASCII stands for American Standard Code for Information Interchange. The complete ASCII table can be found at the following address:

https://www.cs.cmu.edu/~pattis/15-1XX/common/handouts/ascii.html

Examples

Now that you understand the isalpha() function and its syntax, let us look at a few examples:

  • Example 1: Upper-Case Alphabets
  • Example 2: Lower-Case Alphabets
  • Example 3: Digits
  • Example 4: Special Characters
  • Example 5: Practical Usage

Example 1: Upper-Case Alphabets

In this example, you will see how the isalpha() function detects upper-case alphabets.

#include <stdio.h>
#include <ctype.h>
   
int main()
{
    char char_input_1 = 'A';
    char char_input_2 = 'B';
    char char_input_3 = 'M';
    char char_input_4 = 'Y';
    char char_input_5 = 'Z';
   
    /* Check if char_input_1 is an alphabet */
    if(isalpha(char_input_1))
        printf("%c is an alphabet.\n",char_input_1);
    else
        printf("%c is not an alphabet.\n",char_input_1);
       
       
    /* Check if char_input_2 is an alphabet */
    if(isalpha(char_input_2))
        printf("%c is an alphabet.\n",char_input_2);
    else
        printf("%c is not an alphabet.\n",char_input_2);
       
       
    /* Check if char_input_3 is an alphabet */
    if(isalpha(char_input_3))
        printf("%c is an alphabet.\n",char_input_3);
    else
        printf("%c is not an alphabet.\n",char_input_3);
       
       
    /* Check if char_input_4 is an alphabet */
    if(isalpha(char_input_4))
        printf("%c is an alphabet.\n",char_input_4);
    else
        printf("%c is not an alphabet.\n",char_input_4);
       
       
    /* Check if char_input_5 is an alphabet */
    if(isalpha(char_input_5))
        printf("%c is an alphabet.\n",char_input_5);
    else
        printf("%c is not an alphabet.\n",char_input_5);
   
       
    return 0;
}

Example 2: Lower-Case Alphabets

In this example, you will see how the isalpha() function detects lower-case alphabets and returns a non-zero integer value.

#include <stdio.h>
#include <ctype.h>
   
int main()
{
    char char_input_1 = 'a';
    char char_input_2 = 'b';
    char char_input_3 = 'm';
    char char_input_4 = 'y';
    char char_input_5 = 'z';
   
    /* Check if char_input_1 is an alphabet */
    if(isalpha(char_input_1))
        printf("%c is an alphabet.\n",char_input_1);
    else
        printf("%c is not an alphabet.\n",char_input_1);
       
       
    /* Check if char_input_2 is an alphabet */
    if(isalpha(char_input_2))
        printf("%c is an alphabet.\n",char_input_2);
    else
        printf("%c is not an alphabet.\n",char_input_2);
       
       
    /* Check if char_input_3 is an alphabet */
    if(isalpha(char_input_3))
        printf("%c is an alphabet.\n",char_input_3);
    else
        printf("%c is not an alphabet.\n",char_input_3);
       
       
    /* Check if char_input_4 is an alphabet */
    if(isalpha(char_input_4))
        printf("%c is an alphabet.\n",char_input_4);
    else
        printf("%c is not an alphabet.\n",char_input_4);
       
       
    /* Check if char_input_5 is an alphabet */
    if(isalpha(char_input_5))
        printf("%c is an alphabet.\n",char_input_5);
    else
        printf("%c is not an alphabet.\n",char_input_5);
   
       
    return 0;
}

Example 3: Digits

In this example, you will see that the isalpha() function returns zero when we pass numerical digits.

#include <stdio.h>
#include <ctype.h>
   
int main()
{
    char char_input_1 = '0';
    char char_input_2 = '1';
    char char_input_3 = '2';
    char char_input_4 = '3';
    char char_input_5 = '4';
   
    /* Check if char_input_1 is an alphabet */
    if(isalpha(char_input_1))
        printf("%c is an alphabet.\n",char_input_1);
    else
        printf("%c is not an alphabet.\n",char_input_1);
       
       
    /* Check if char_input_2 is an alphabet */
    if(isalpha(char_input_2))
        printf("%c is an alphabet.\n",char_input_2);
    else
        printf("%c is not an alphabet.\n",char_input_2);
       
       
    /* Check if char_input_3 is an alphabet */
    if(isalpha(char_input_3))
        printf("%c is an alphabet.\n",char_input_3);
    else
        printf("%c is not an alphabet.\n",char_input_3);
       
       
    /* Check if char_input_4 is an alphabet */
    if(isalpha(char_input_4))
        printf("%c is an alphabet.\n",char_input_4);
    else
        printf("%c is not an alphabet.\n",char_input_4);
       
       
    /* Check if char_input_5 is an alphabet */
    if(isalpha(char_input_5))
        printf("%c is an alphabet.\n",char_input_5);
    else
        printf("%c is not an alphabet.\n",char_input_5);
   
       
    return 0;
}

Example 4: Special Characters

In this example, you will see that the isalpha() function returns zero when we pass special characters.

#include <stdio.h>
#include <ctype.h>
   
int main()
{
    char char_input_1 = '&';
    char char_input_2 = '$';
    char char_input_3 = '#';
    char char_input_4 = '%';
    char char_input_5 = '@';
   
    /* Check if char_input_1 is an alphabet */
    if(isalpha(char_input_1))
        printf("%c is an alphabet.\n",char_input_1);
    else
        printf("%c is not an alphabet.\n",char_input_1);
       
       
    /* Check if char_input_2 is an alphabet */
    if(isalpha(char_input_2))
        printf("%c is an alphabet.\n",char_input_2);
    else
        printf("%c is not an alphabet.\n",char_input_2);
       
       
    /* Check if char_input_3 is an alphabet */
    if(isalpha(char_input_3))
        printf("%c is an alphabet.\n",char_input_3);
    else
        printf("%c is not an alphabet.\n",char_input_3);
       
       
    /* Check if char_input_4 is an alphabet */
    if(isalpha(char_input_4))
        printf("%c is an alphabet.\n",char_input_4);
    else
        printf("%c is not an alphabet.\n",char_input_4);
       
       
    /* Check if char_input_5 is an alphabet */
    if(isalpha(char_input_5))
        printf("%c is an alphabet.\n",char_input_5);
    else
        printf("%c is not an alphabet.\n",char_input_5);
   
       
    return 0;
}

Example 5: Practical Usage

In this example, we will look into the practical usage of the isalpha() function in a real-world situation. Suppose that we are receiving an input character stream and we need to extract the meaningful alphabets from it. We can use the islpha() function to extract the alphabets from the input stream.

#include <stdio.h>
#include <ctype.h>
   
   
int main()
{
    char char_input[] = "5673&^%_SOF2*!";
    char char_output[10];
    int i = 0, j = 0;
   
    while(char_input[i] != '\0')
    {
        if(isalpha(char_input[i]))
        {
            char_output[j] = char_input[i];
            j++;
        }
        i++;
    }
    char_output[j] = '\0';
   
    printf("char_output = %s\n",char_output);  
       
    return 0;
}

Conclusion

In multiple examples of the practical usage of the isalpha() function, this article showed you how the isalpha() function plays a key role in detecting alphabet characters in the C programming language. This function is mainly used in embedded programming, where we receive a stream of characters and we need to extract meaningful alphabets from the input stream.

]]>
Sizeof operator in C language https://linuxhint.com/sizeof_c_language/ Fri, 11 Sep 2020 11:00:20 +0000 https://linuxhint.com/?p=68224 In this article, we are going to learn about the sizeof operator in C. It is a widely used unary operator in the embedded software development, which helps us to find out the size of the operand. Therefore, the return value of the sizeof operator helps us to understand the number of bytes allocated in the computer memory to hold the particular variable or data type.

Understanding Sizeof:

Before we dive into the sizeof operator discussion, Let us first understand the meaning of the operator. An Operator is represented by a token or symbol which is used to perform an operation such as addition, subtraction, multiplication, division, etc. upon values or variables (Operands). For example, “*” is the symbol that is used to represent the multiplication operation, and it works on two operands (result = a * b ;). This is an example of a binary operator.

However, if an operator works upon only one operand, we call such an operator as a unary operator. The sizeof operator is one of the unary operators that exist in C programming language and apparently, it operates only on one operand. The sizeof operator returns the size of the operand. That means, from the return value of Sizeof operator, we can clearly say how many bytes allocated to hold the particular operand in the computer memory.

A computer’s memory is a collection of memory units (i.e. byte). When sizeof (int) returns four in a particular computer system, we can say that an integer variable takes 4 bytes to hold its value in that specific computer system’s memory. Also, please note that the return value of the sizeof operator also depends on the machines that you are using (32-bit system or 64-bit system).

Syntax:

Sizeof(type)
Sizeof(expression)

The return type of sizeof is size_t.

Examples:

Now since we understand the sizeof operator and know the syntax, let us look at a couple of examples, which will help us to understand the concept in a better way.

  • Sizeof for built-in types (example1.c)
  • Sizeof for Array (example2.c)
  • Sizeof for user-defined types (example3.c)
  • Sizeof for variables (example4.c)
  • Sizeof for expression (example5.c)
  • Practical usage of sizeof (example6.c)

Sizeof for built-in types (example1.c):

In this program, we will see how the sizeof operator works for built-in data types such as int, char, float, double. Let us look at the program and output.

#include <stdio.h>
   
int main()
{
    printf("Size of char   =  %ld \n", sizeof(char));
    printf("Size of int    =  %ld \n", sizeof(int));
    printf("Size of float  =  %ld \n", sizeof(float));
    printf("Size of double =  %ld \n\n", sizeof(double));
   
    printf("Size of short int      =  %ld \n", sizeof(short int));
    printf("Size of long int       =  %ld \n", sizeof(long int));
    printf("Size of long long int  =  %ld \n", sizeof(long long int));
    printf("Size of long double    =  %ld \n", sizeof(long double));
   
    return 0;
}

Sizeof for Array (example2.c)

In this program, we will see how to use the sizeof operator for different types of array. In case of an array, the sizeof operator will return (No. of elements in the array * Sizeof (array type)). For example, when we declare an integer type array of 10 elements (int SmartPhones [10] ;), the sizeof(Smartphones) will return:

(No. of elements in SmartPhones * sizeof(int)) = (10 * 4) = 40

Let us look at the program and output.

#include <stdio.h>

int main()
{
    int SmartPhones[10];
    char SmartPhoneNames[10];
    double SmartPhonesPrice[10];
   
    printf("Size of int     =  %ld \n", sizeof(int));
    printf("Size of char    =  %ld \n", sizeof(char));
    printf("Size of double  =  %ld \n", sizeof(double));
   
   
    /* Find out the sizeof Array*/
    printf("Size of SmartPhones[10]       =  %ld \n", sizeof(SmartPhones));
    printf("Size of SmartPhoneNames[10]   =  %ld \n", sizeof(SmartPhoneNames));
    printf("Size of SmartPhonesPrice[10]  =  %ld \n", sizeof(SmartPhonesPrice));
   

    return 0;
}

Sizeof for user-defined types(example3.c):

In this example, we will see how to use sizeof operator for user-defined data types such as structure and union. Let’s use the program and understand the output.

Now, looking at the program, and we can manually calculate the size of SmartPhoneType. As you can see below, SmartPhoneType is a structure, and it contains the following elements:

  • Number of character type variable = 1 [sp_name]
  • Number of integer type variable= 1 [sp_version]
  • Number of float type variables= 3 [sp_length, sp_width, sp_height]

From the example-1, we have seen that:

    • Size of character is 1 byte
    • Size of an integer is 4 bytes
    • Size of a float is 4 bytes

Therefore, if we add up the size of all the elements in the structure, we should be able to get the size of the structure, i.e. SmartPhoneType. Therefore, the size of the structure should be = (1 + 4 + 4 + 4 + 4) bytes = 17 bytes. However, the program output says the structure size is 20. The extra 3 bytes (sp_name, which is a character, is taking 4 bytes instead of 1 byte) allocated for the structure due to the structure padding.

#include <stdio.h>

/* Create an user defined structure type - SmartPhoneType*/
struct SmartPhoneType
{
    char  sp_name;
    int   sp_version;
    float sp_length;
    float sp_width;
    float sp_height;
}SmartPhone;


/* Define an user defined union type - SmartPhoneUnionType*/
Union SmartPhoneUnionType
{
    char  sp_name;
    int   sp_version;
    float sp_length;
    float sp_width;
    float sp_height;
}SmartPhone_u;

   
int main()
{
    /* Find out the size of structure and union*/
    printf("Size of struct   =  %ld \n", sizeof(SmartPhone));
    printf("Size of union    =  %ld \n", sizeof(SmartPhone_u));
   
    return 0;
}

Sizeof for variables (example4.c):

This example program illustrates that the sizeof operator is capable of accepting the variable also and return the size of the variable.

#include <stdio.h>
   
int main()
{
    /* Declare char, int, float and double type variable and array */
    char   var_a, var_b[20];
    int    var_c, var_d[20];
    float  var_e, var_f[20];
    double var_g, var_h[20];
   
   
    /* Find out the size of variables and array.
       This program demonstrates that variable can also
       be used as an operand sizeof operator*/

   
    /* size of char, char variable and char array*/
    printf("Size of char        =  %ld \n", sizeof(char));
    printf("Size of var_a       =  %ld \n", sizeof(var_a));
    printf("Size of var_b[20]   =  %ld \n\n", sizeof(var_b));
   
   
    /* size of int, int variable and int array*/
    printf("Size of int         =  %ld \n", sizeof(int));
    printf("Size of var_c       =  %ld \n", sizeof(var_c));
    printf("Size of var_d[20]   =  %ld \n\n", sizeof(var_d));
   
   
    /* size of float, float variable and float array*/
    printf("Size of float       =  %ld \n", sizeof(float));
    printf("Size of var_e       =  %ld \n", sizeof(var_e));
    printf("Size of var_f[20]   =  %ld \n\n", sizeof(var_f));
   
   
    /* size of double, double variable and double array*/
    printf("Size of double      =  %ld \n", sizeof(double));
    printf("Size of var_g       =  %ld \n", sizeof(var_g));
    printf("Size of var_h[20]   =  %ld \n", sizeof(var_h));
   
    return 0;
}

Sizeof for expression(example5.c):

In this example program, we will demonstrate that the sizeof operator can also accept an expression and return the size of the resulting expression.

#include <stdio.h>

int main()
{
    int    var_a = 5, var_b = 3;
    double  var_c = 2.5, var_d = 4.5;
   
    printf("Size of int     =  %ld \n", sizeof(int));
    printf("Size of double  =  %ld \n\n", sizeof(double));
   
    printf("Size of var_a * var_b   =  %ld \n", sizeof(var_a * var_b));
    printf("Size of var_c * var_d   =  %ld \n", sizeof(var_c * var_d));
   
   
    /* Here we are multiplying an integer variable with a double variable.
       Therefore, sizeof operator will return the size of maximum sized
       variable i.e. double type variable.*/

    printf("Size of var_a * var_c   =  %ld \n", sizeof(var_a * var_c));
   
    return 0;
}

Practical usage of sizeof (example6.c):

This example program will help you to understand a practical use case of the sizeof operator. The Sizeof operator is very much useful while allocating the dynamic memory from heap using malloc. Let us look at the program and the output.

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

typedef struct
{
    char  sp_name;
    int   sp_version;
    float sp_length;
    float sp_width;
    float sp_height;
} SmartPhoneType;

int main()
{
    /* Allocate memory in the Heap memory for holding five SmartPhoneType
       variables.
    */

    SmartPhoneType * SmartPhone_Ptr = (SmartPhoneType *)malloc(5 * sizeof(SmartPhoneType));
   
    if(SmartPhone_Ptr != NULL)
    {
        printf("Memory allocated for 5 SmartPhoneType structure variables in
                        the Heap memory.\n"
);
       
    }
    else
    {
        printf("Error occured during the heap memory allocation!");
    }
       
   
    return 0;
}

Conclusion:

The Sizeof is an important unary operator in the C programming language. It helps us in determining the size of primitive data types, user-defined data types, expressions, etc. in computer memory. The Sizeof operator plays an important role in allocating dynamic memory in C using malloc, calloc, etc. in the Heap memory.

]]>
String Comparison: C Programming https://linuxhint.com/comparing_strings_c_language/ Sat, 05 Sep 2020 11:15:18 +0000 https://linuxhint.com/?p=67511 A string in C language is an array of characters, which is terminated with a null character (\0). Using this property strings are compared.

Two strings can be compared in various ways. In this tutorial, first, we will see a user-defined function to compare two strings, and then we will see some built-in library functions which can be used to compare two strings very easily. So, let’s get started.

String comparison using a user-defined function :

We will write a function stringCompare() to compare strings. We traverse the strings and compare each character of the string until we reach the end of any one or both or one mismatched are found. If the traversal is reached to the end of both the strings, then the strings are matched; otherwise, strings are mismatched.

01. /*userDefinedFunction.c*/  
02.  
03. #include<stdio.h>    
04.    
05. int stringCompare( char str1[ ], char str2[ ] )    
06. {    
07.     int i=0;    
08.    
09.     while( str1[i] == str2[i] )    
10.     {    
11.         if( str1[i] == '\0' || str2[i] == '\0' )    
12.             break;    
13.         i++;    
14.     }    
15.    
16.     if( str1[i] == '\0' &&  str2[i] == '\0' )    
17.         return 0;    
18.     else    
19.         return -1;    
20.    
21. }    
22.    
23.    
24. int  main()    
25. {    
26.     char str1[30],str2[30];    
27.    
28.     printf("Enter the first string: ");  
29.     scanf("%[^\n]%*c",str1);  
30.     printf("Enter the second string: ");  
31.     scanf("%[^\n]%*c",str2);  
32.  
33.     if(stringCompare(str1,str2) == 0)  
34.         printf("The strings are equal \n");    
35.     else  
36.         printf("The strings are not equal \n");    
37.    
38.     return 0;    39.    }

Here we traverse the strings using while loop and a variable i. When characters are equal in the same position of both strings, the value of i is incremented by 1 (line 13). If characters are not equal (line 09) or we reach the end of the string (line 11), then the while loop is a break. After the while loop, we check both the string traversals are reached to the end or not (line 16). If the traversal is reached to the end of both strings, then the strings are equal otherwise not.

String comparison using built-in library functions :

The following library functions can be used for string comparison. All the functions are declared in the string.h header file.

strcmp() function :

This function compares two strings passed to the function.

Syntax:

int strcmp(const char *str1, const char *str2)

Return value: Return 0 if the strings are equal. Return a negative integer if the ASCII value of the first unmatched character of the first string is less than the second string. Return a positive integer if the ASCII value of the first unmatched character of the first string is greater than the second string. Some systems return difference of the ASCII value of first mismatched character and some systems return -1 if the ASCII value of the first unmatched character of the first string is less than the second string and return 1 if the ASCII value of the first unmatched character of the first string is greater than the second string.

Example Return Value Explanation
strcmp( “Hello World”,”Hello World” ) 0 Two strings are the same.
strcmp( “Hello”,”Hello\0 World” ) 0 Strings are compared till the character ‘\0’. The first string by default ends with ‘\0’, and the second string contains the ‘\0’ character after ‘Hello’.
strcmp( “Hello\0\0\0″,”Hello\0 World” ) 0 Strings are compared till the character ‘\0’.
strcmp( “Hello World”,”hello World” ) Negative integer ASCII value of the first unmatched character of the first string (‘H’) is less than the second string (‘h’)
strcmp(“hello World”,”Hello World” ) Positive integer ASCII value of the first unmatched character of the first string (‘h’) is greater than the second string (‘H’)

strncmp() function :

This function is similar to the function strcmp(), but here we have to specify how many bytes are compared by passing an extra argument to the function.

Syntax:

int strncmp(const char *str1, const char *str2, size_t n)

Return value: The function returns 0 if the first n characters of the two strings are equal; otherwise, it returns negative or positive integer depending on the sign of the differences between the first mismatched character’s ASCII value.

Example Return Value Explanation
strncmp( “Hello World”,”Hello World”,5 ) 0 First 5 characters are the same.
strncmp( “Hello”,”Hello\0 World”,5 ) 0 First 5 characters are the same.
strncmp( “Hello\0\0\0″,”Hello\0 World”,8 ) 0 ‘\0’ is after the first 5 characters in both strings. So, comparison is stopped after 5 not 8.
strncmp( “Hello World”,”hello World”,5 ) Negative integer ASCII value of the first unmatched character of the first string (‘H’) is less than the second string (‘h’)

strcasecmp() function :

This function is similar to the function strcmp(), but here the strings are not case sensitive.

Syntax:

int strcasecmp(const char *str1, const char *str2)

Return value: Same as strcmp(), but strings are treated as case-in-sensitive.

Example Return Value Explanation
strcasecmp( “Hello World”,”Hello World” ) 0 Two strings are the same.
strcasecmp( “Hello”,”Hello\0 World” ) 0 Strings are compared till the character ‘\0’. The first string by default ends with ‘\0’, and the second string contain the ‘\0’ character after ‘Hello’.
strcasecmp( “Hello World”,”hello World” ) 0 Strings are case-in-sensitive. So, “Hello World” and “hello World” are the same.

strncasecmp() function :

This function is similar to the function strncmp(), but here the strings are not case sensitive.

Syntax:

int strncasecmp(const char *str1, const char *str2)

Return value: Same as strncmp(), when strings are treated as case-in-sensitive.

Example Return Value Explanation
strncasecmp( “Hello World”,”Hello World”,5 ) 0 First 5 characters are the same.
strncasecmp( “Hello”,”Hello\0 World”,5 ) 0 First 5 characters are the same.
strncasecmp( “Hello\0\0\0″,”Hello\0 World”,8 ) 0 ‘\0’ is after the first 5 characters in both strings. So, comparison is stopped after 5 not 8.
strncasecmp( “Hello World”,”hello World”,5 ) 0 Strings are case-in-sensitive. So, “Hello” and “hello” are the same.

memcmp() function :

This function compares two memory blocks byte by byte. We have to pass two pointers of the memory blocks and the number of bytes to compare.

Syntax:

int memcmp(const void *str1, const void *str2, size_t n)

Return value: The function returns 0 if the two memory blocks (n bytes) are equal; otherwise, it returns the differences between the first mismatched pair of bytes (bytes are interpreted as unsigned char objects, then promoted to int).

Example Return Value Explanation
memcmp( “Hello World”,”Hello World”,5 ) 0 First 5 characters are the same.
memcmp( “Hello\0\0\0″,”Hello\0 World”,8 ) Negative integer The first 6 characters are the same, but the 7th character is different. Here comparison not stopped like strncmp() when getting ‘\0’ character.
memcmp( “Hello World”,”hello World”,11 ) Negative integer ASCII value of the first unmatched character of the first string (‘H’) is less than the second string (‘h’)

Example:

Following is the C code example of all the functions discussed.

01. /*stringCompare.c*/    
02.  
03. #include<stdio.h>    
04. #include<string.h>    
05.  
06. int main()    
07. {    
08. printf("strcmp( "Hello World","Hello World" ) => %d\n",strcmp( "Hello World","Hello World" ));    
09. printf("strcmp( "Hello","Hello\\0 World" ) => %d\n",strcmp( "Hello","Hello\0 World" ));    
10. printf("strcmp( "Hello World","hello World" ) => %d\n",strcmp( "Hello World","hello World" ) );    
11. printf("strcmp( "Hello\\0\\0\\0","Hello\\0 World" ) => %d\n",strcmp( "Hello\0\0\0","Hello\0 World" ));    
12.  
13. printf("\n---------------\n");    
14.  
15. printf("strncmp( "Hello World","Hello World",5 ) => %d\n",strncmp( "Hello World","Hello World",5 ));    
16. printf("strncmp( "Hello","Hello\\0 World",5 ) => %d\n",strncmp( "Hello","Hello\0 World",5 ));    
17. printf("strncmp( "Hello\\0\\0\\0","Hello\\0 World",8 ) => %d\n",strncmp( "Hello\0\0\0","Hello\0 World",8 ));    
18. printf("strncmp( "Hello World","hello World",5 ) => %d\n",strncmp( "Hello World","hello World",5 ));    
19.  
20. printf("\n---------------\n");    
21.  
22. printf("strcasecmp( "Hello World","Hello World" ) => %d\n",strcasecmp( "Hello World","Hello World" ));    
23. printf("strcasecmp( "Hello","Hello\\0 World" ) => %d\n",strcasecmp( "Hello","Hello\0 World" ));    
24. printf("strcasecmp( "Hello World","hello World" ) => %d\n",strcasecmp( "Hello World","hello World" ));    
25.  
26. printf("\n---------------\n");    
27.  
28. printf("strncasecmp( "Hello World","Hello World",5 ) => %d\n",strncasecmp( "Hello World","Hello World",5 ) );    
29. printf("strncasecmp( "Hello","Hello\\0 World",5 ) => %d\n",strncasecmp( "Hello","Hello\0 World",5 ));    
30. printf("strncasecmp( "Hello\\0\\0\\0","Hello\\0 World",8 ) => %d\n",strncasecmp( "Hello\0\0\0","Hello\0 World",8 ));    
31. printf("strncasecmp( "Hello World","hello World",5 ) => %d\n",strncasecmp( "Hello World","hello World",5 ));    
32.  
33. printf("\n---------------\n");    
34.  
35. printf("memcmp( "Hello World","Hello World",5 ) => %d\n",memcmp( "Hello World","Hello World",5 ) );    
36. printf("memcmp( "Hello\\0\\0\\0","Hello\\0 World",8 ) => %d\n",memcmp( "Hello\0\0\0","Hello\0 World",8 ));    
37. printf("memcmp( "Hello World","hello World",11 ) => %d\n",memcmp( "Hello World","hello World",11 ));    
38.  
39. return 0;    40.    }

Conclusion:

So, in this tutorial, we have seen how strings can be compared in various ways. As we have seen, the stringCompare() function returns -1 for unequal strings, but this can be modified so that it returns ASCII value of mismatched character. You can use it in your code, which is best suited for you.

]]>
How to use enum in C Language https://linuxhint.com/use_enum_c_language/ Fri, 04 Sep 2020 18:44:41 +0000 https://linuxhint.com/?p=67315 The enum program in the C programming language is used to define integral constant values, which is very helpful in writing clean and readable programs. Programmers normally use enumeration to define named integral constants in their programs to provide better readability and maintainability of the software. This article will discuss enum in detail.

Syntax

enum  <Enum Type Name> {
Enumeration_Constant_Element-1,  
Enumeration_Constant_Element-2,  
Enumeration_Constant_Element-3,  
…….........,
Enumeration_Constant_Element-n,  
    };

The default value of Enumeration_Constant_Element-1 is 0, the value of Enumeration_Constant_Element-2 is 1, the value of Enumeration_Constant_Element-3 is 2, and the value of Enumeration_Constant_Element-n is (n-1).

Deep Dive into Enum

Now, since we know the syntax to define the enumeration type, let us look at an example:

enum Error {   
             IO_ERROR,
             DISK_ERROR,
             NETWORK_ERROR
           };

The “enum” keyword must always be used to define the enumeration type. So, whenever you want to define an enumeration type, you must use the “enum” keyword before <Enum Type Name>. After the “enum” keyword, you must use a valid identifier to define the <Enum Type Name>.

In the above example, the compiler will assign IO_ERROR to the integral value: 0, DISK_ERROR to the integral value: 1 and NETWORK_ERROR to the integral value: 2.  By default, the first enum-element is always assigned the value 0, the next enum-element is assigned the value 1, and so on.

This default behaviour can be changed if necessary by assigning the constant integral value explicitly, as follows:

enum Error {   
IO_ERROR = 2,
            DISK_ERROR,
            NETWORK_ERROR = 8 ,
        PRINT_ERROR
           };

In this case, the IO_ERROR is explicitly assigned to a value of 2 by the programmer, DISK_ERROR is assigned to a value of 3 by the compiler, NETWORK_ERROR is explicitly assigned to the value of 8 by the programmer, and PRINT_ERROR is assigned to the next integral value of the previous enum element NETWORK_ERROR (i.e., 9) by the compiler.

So, you now understand how to define a user-defined enumeration type in C. Is it possible to declare a variable of enum type (as we can declare a variable of integer type)?  Yes, it is! You can declare the enum variable as follows:

enum Error Hw_Error;

Again, “enum” is the keyword here, “Error” is the enum type, and  “Hw_Error” is an enum variable.

We will now look at the following examples to understand the various usages of enum:

  • Example 1: Default enum definition usage
  • Example 2: Custom enum definition usage
  • Example 3: enum definition using constant expression
  • Example 4: enum scope

Example 1: Default enum Definition Usage

In this example, you will learn how to define the enumeration type with default constant values. The compiler will take care of assigning the default values to the enum elements. Below, you will see the example program and the corresponding output.

#include <stdio.h>

/* Define the enum type */
enum Error {
    IO_ERROR,
    DISK_ERROR,
    NETWORK_ERROR
    };
   
int main()
{
    enum Error Hw_Error;    /* Creating enum variable*/

    printf("Setting Hw_Error to IO_ERROR\n");
    Hw_Error = IO_ERROR;
    printf("Value of Hw_Error = %d \n",Hw_Error);

    printf("\nSetting Hw_Error to DISK_ERROR\n");
    Hw_Error = DISK_ERROR;
    printf("Value of Hw_Error = %d \n",Hw_Error);

    printf("\nSetting Hw_Error to NETWORK_ERROR\n");
    Hw_Error = NETWORK_ERROR;
    printf("Value of Hw_Error = %d \n",Hw_Error);

    return 0;
}

https://lh6.googleusercontent.com/0CHtUqkuIA-okDEPI0_5fZLU6lZ6Exz6DK4uUr63k5Ros863eqC-HmrvZ_LZBKbEvqeCVMCsnvXXhfrYJrBaxxfZBVoiMOHPzXeyxqQnCVf4hz0D4AJ-mPRJWjhIGA

Example 2: Custom enum Definition Usage

In this example, you will learn how to define the enumeration type with a custom constant value. Also, this example will help you understand how the custom constants initialization can be done in any random order. In this example, we have explicitly defined the constant value for the 1st and 3rd enum elements (i.e., IO_ERROR and NETWORK_ERROR, respectively), but we have skipped the explicit initialization for the 2nd and 4th elements. It is now the responsibility of the compiler to assign the default values to the 2nd and 4th enum elements (i.e., DISK_ERROR and PRINT_ERROR, respectively). DISK_ERROR will be assigned to a value of 3 and PRINT_ERROR will be assigned to a value of 9. Below, you will see the example program and the output.

#include <stdio.h>

/* Define the enum type  - Custom initialization*/
enum Error {
    IO_ERROR = 2,
    DISK_ERROR,
    NETWORK_ERROR = 8,
    PRINT_ERROR
    };
   
int main()
{

    /* Declare enum variable*/
    enum Error Hw_Error;

    printf("Setting Hw_Error to IO_ERROR\n");
    Hw_Error = IO_ERROR;
    printf("Value of Hw_Error = %d \n",Hw_Error);

    printf("\nSetting Hw_Error to DISK_ERROR\n");
    Hw_Error = DISK_ERROR;
    printf("Value of Hw_Error = %d \n",Hw_Error);

    printf("\nSetting Hw_Error to NETWORK_ERROR\n");
    Hw_Error = NETWORK_ERROR;
    printf("Value of Hw_Error = %d \n",Hw_Error);
   
    printf("\nSetting Hw_Error to PRINT_ERROR\n");
    Hw_Error = PRINT_ERROR;
    printf("Value of Hw_Error = %d \n",Hw_Error);

    return 0;
}

https://lh6.googleusercontent.com/hKtv00Hj7iPnnlNhC7mu1v7hzPhB64C9nyHwjB6oQgyCyEwOgiLSYWDOxvQCDrhumn4IzqhkN4qF9HcuGZ9thqlBLy6hsv9F-FwKl2EnUjzx0af4UwDK0agfEVv0rA

Example 3: Enum Definition Using Constant Expression

In this example, you will learn how to use the constant expression to define the constant value for enum elements.

#include <stdio.h>

/* Define the enum type - custom initialization using constant expression
   constant expression is being used here in case of :
    a. IO_ERROR and
    b. NETWORK_ERROR
   This is an unusual way of defining the enum elements; however, this
program demonstrates that this way of enum elements initialization is possible in c.
*/


enum Error {
    IO_ERROR = 1 + 2 * 3 + 4,
    DISK_ERROR,
    NETWORK_ERROR = 2 == 2,
    PRINT_ERROR
    };
   
int main()
{

    /* Declare enum variable*/
    enum Error Hw_Error;

    printf("Setting Hw_Error to IO_ERROR\n");
    Hw_Error = IO_ERROR;
    printf("Value of Hw_Error = %d \n",Hw_Error);

    printf("\nSetting Hw_Error to DISK_ERROR\n");
    Hw_Error = DISK_ERROR;
    printf("Value of Hw_Error = %d \n",Hw_Error);

    printf("\nSetting Hw_Error to NETWORK_ERROR\n");
    Hw_Error = NETWORK_ERROR;
    printf("Value of Hw_Error = %d \n",Hw_Error);
   
    printf("\nSetting Hw_Error to PRINT_ERROR\n");
    Hw_Error = PRINT_ERROR;
    printf("Value of Hw_Error = %d \n",Hw_Error);

    return 0;
}

https://lh4.googleusercontent.com/9FAbPOnM95LiP_UQvg40oHSW4sv34aqpFgasbHMiy06Z_rKEom81TuMCVsfxWaZedtQOMEQx7ef_5qEfRVcNrUvhitDzOcTvYXregm4Udaby1NmwOil_Qhpr_oD4UQ

Example 4: enum Scope

In this example, you will learn how the scoping rule works for enum. A MACRO (#define) could have been used to define a constant instead of the enum, but the scoping rule does not work for MACRO.

#include <stdio.h>

int main()
{

    /* Define the enum type */
    enum Error_1 {
            IO_ERROR = 10,
            DISK_ERROR,
            NETWORK_ERROR = 3,
            PRINT_ERROR
             };
   

    {
   
        /* Define the enum type in the inner scope*/
        enum Error_1 {
                IO_ERROR = 20,
                DISK_ERROR,
                NETWORK_ERROR = 35,
                PRINT_ERROR
                 };

        /* Declare enum variable*/
        enum Error_1 Hw_Error;
        printf("Setting Hw_Error to IO_ERROR\n");
        Hw_Error = IO_ERROR;
        printf("Value of Hw_Error = %d \n",Hw_Error);

        printf("\nSetting Hw_Error to DISK_ERROR\n");
        Hw_Error = DISK_ERROR;
        printf("Value of Hw_Error = %d \n",Hw_Error);

        printf("\nSetting Hw_Error to NETWORK_ERROR\n");
        Hw_Error = NETWORK_ERROR;
        printf("Value of Hw_Error = %d \n",Hw_Error);
   
        printf("\nSetting Hw_Error to PRINT_ERROR\n");
        Hw_Error = PRINT_ERROR;
        printf("Value of Hw_Error = %d \n",Hw_Error);
    }
    return 0;
}

Comparison Between enum and macro

Enum Macro
Scoping rule is applicable for enum. Scoping rule is not applicable for Macro.
Default Enum value assignment happens automatically.

Enum is very helpful in defining a large number of constants. The compiler takes the default constant value initialization.

The macro constant values must always be mentioned explicitly by the programmer.

This could be a tedious process for a large number of constants since the programmer must always manually define each constant value while defining the Macro.

Conclusion

The enum program in C could be considered an optional method for standalone programs or small-sized projects since programmers can always use macro instead of an enum. However, experienced programmers tend to use enum over macro for large-scale software development projects. This helps in writing clean and readable programs.

]]>