Functions in C-2 | Programming and Data Structures - Computer Science Engineering (CSE) PDF Download

Functions that are executed before and after main() in C

With GCC family of C compilers, we can mark some functions to execute before and after main(). So some startup code can be executed before main() starts, and some cleanup code can be executed after main() ends. For example, in the following program, myStartupFun() is called before main() and myCleanupFun() is called after main().
#include<stdio.h>
/* Apply the constructor attribute to myStartupFun() so that it
    is executed before main() */
void myStartupFun (void) __attribute__ ((constructor));
/* Apply the destructor attribute to myCleanupFun() so that it
   is executed after main() */
void myCleanupFun (void) __attribute__ ((destructor));
/* implementation of myStartupFun */
void myStartupFun (void)
{
    printf ("startup code before main()\n");
}

/* implementation of myCleanupFun */
void myCleanupFun (void)
{
    printf ("cleanup code after main()\n");
}
int main (void)
{
    printf ("hello\n");
    return 0;
}
Output:
startup code before main()
hello
cleanup code after main()

Static functions in C

Prerequisite: Static variables in C
In C, functions are global by default. The “static” keyword before a function name makes it
static. For example, below function fun() is static.
static int fun(void)
{
  printf("I am a static function ");
}
Unlike global functions in C, access to static functions is restricted to the file where they are declared. Therefore, when we want to restrict access to functions, we make them static. Another reason for making functions static can be reuse of the same function name in other files.
For example, if we store following program in one file file1.c
/* Inside file1.c */
static void fun1(void)
{
  puts("fun1 called");
}
And store following program in another file file2.c
/* Inside file2.c  */
int main(void)
{
  fun1();
  getchar();
  return 0;  
}
Now, if we compile the above code with command “gcc file2.c file1.c”, we get the error “undefined reference to `fun1’” . This is because fun1() is declared static in file1.c and cannot be used in file2.c.

return statement vs exit() in main()

In C++, what is the difference between exit(0) and return 0?
When exit(0) is used to exit from program, destructors for locally scoped non-static objects are not called. But destructors are called if return 0 is used.

Program 1 – – uses exit(0) to exit
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
using namespace std;
class Test {
public:
  Test() {
    printf("Inside Test's Constructor\n");
  }
  ~Test(){
    printf("Inside Test's Destructor");
    getchar();
  }
};
int main() {
  Test t1;
    // using exit(0) to exit from main
  exit(0);
}
Output:
Inside Test’s Constructor

Program 2 – uses return 0 to exit
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
using namespace std;
class Test {
public:
  Test() {
    printf("Inside Test's Constructor\n");
  }  
  ~Test(){
    printf("Inside Test's Destructor");
  }
};  
int main() {
  Test t1;
   // using return 0 to exit from main
  return 0;
}
Output:
Inside Test’s Constructor
Inside Test’s Destructor
Calling destructors is sometimes important, for example, if destructor has code to release resources like closing files.

Note that static objects will be cleaned up even if we call exit(). For example, see following program.

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
using namespace std;
class Test {
public:
  Test() {
    printf("Inside Test's Constructor\n");
  }
  ~Test(){
    printf("Inside Test's Destructor");
    getchar();
  }
};  
int main() {
  static Test t1;  // Note that t1 is static
  exit(0);
}
Output:
Inside Test’s Constructor
Inside Test’s Destructor

exit(), abort() and assert()

1. exit()
void exit ( int status );
exit() terminates the process normally.
status: Status value returned to the parent process. Generally, a status value of 0 or EXIT_SUCCESS indicates success, and any other value or the constant EXIT_FAILURE is used to indicate an error. exit() performs following operations.
* Flushes unwritten buffered data.
* Closes all open files.
* Removes temporary files.
* Returns an integer exit status to the operating system.
The C standard atexit() function can be used to customize exit() to perform additional actions at program termination.
Example use of exit.
/* exit example */
#include <stdio.h>
#include <stdlib.h>  
int main ()
{
  FILE * pFile;
  pFile = fopen ("myfile.txt", "r");
  if (pFile == NULL)
  {
    printf ("Error opening file");
    exit (1);
  }
  else
  {
    /* file operations here */
  }
  return 0;
}
When exit() is called, any open file descriptors belonging to the process are closed and any children of the process are inherited by process 1, init, and the process parent is sent a SIGCHLD signal.
The mystery behind exit() is that it takes only integer args in the range 0 – 255 . Out of range exit values can result in unexpected exit codes. An exit value greater than 255 returns an exit code modulo 256.
For example, exit 9999 gives an exit code of 15 i.e. (9999 % 256 = 15).

Below is the C implementation to illustrate the above fact:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(void)
{
    pid_t pid = fork();      
    if ( pid == 0 )
    {
       exit(9999); //passing value more than 255
    }
    int status;
    waitpid(pid, &status, 0);
    if ( WIFEXITED(status) )
    {
        int exit_status = WEXITSTATUS(status);
        printf("Exit code: %d\n", exit_status);
    }
return 0;
}
Output:
Exit code: 15

Note that the above code may not work with online compiler as fork() is disabled.

Explanation: It is effect of 8-bit integer overflow. After 255 (all 8 bits set) comes 0.
So the output is “exit code modulo 256”. The output above is actually the modulo of the value 9999 and 256 i.e. 15.

2. abort()
void abort ( void );
Unlike exit() function, abort() may not close files that are open. It may also not delete temporary files and may not flush stream buffer. Also, it does not call functions registered with atexit().
This function actually terminates the process by raising a SIGABRT signal, and your program can include a handler to intercept this signal (see this).
So programs like below might not write “Geeks for Geeks” to “tempfile.txt”
#include<stdio.h>
#include<stdlib.h>
int main()
{
  FILE *fp = fopen("C:\\myfile.txt", "w");    
  if(fp == NULL)
  {
    printf("\n could not open file ");
    getchar();
    exit(1);
  }
  fprintf(fp, "%s", "Geeks for Geeks");    
  /* ....... */
  /* ....... */
  /* Something went wrong so terminate here */  
  abort();
  getchar();
  return 0;
}
If we want to make sure that data is written to files and/or buffers are flushed then we should either use exit() or include a signal handler for SIGABRT.

3. assert()
void assert( int expression );
If expression evaluates to 0 (false), then the expression, sourcecode filename, and line number are sent to the standard error, and then abort() function is called. If the identifier NDEBUG (“no debug”) is defined with #define NDEBUG then the macro assert does nothing.
Common error outputting is in the form:
Assertion failed: expression, file filename, line line-number
#include<assert.h>
void open_record(char *record_name)
{
    assert(record_name != NULL);
    /* Rest of code */
}
int main(void)
{
   open_record(NULL);
}

Implicit return type int in C

Predict the output of following C program.
#include <stdio.h>
fun(int x)
{
    return x*x;
}
int main(void)
{
    printf("%d", fun(10));
    return 0;
}
Output: 100
The important thing to note is, there is no return type for fun(), the program still compiles and runs fine in most of the C compilers. In C, if we do not specify a return type, compiler assumes an implicit return type as int. However, C99 standard doesn’t allow return type to be omitted even if return type is int. This was allowed in older C standard C89.
In C++, the above program is not valid except few old C++ compilers like Turbo C++. Every function should specify the return type in C++.

The document Functions in C-2 | Programming and Data Structures - Computer Science Engineering (CSE) is a part of the Computer Science Engineering (CSE) Course Programming and Data Structures.
All you need of Computer Science Engineering (CSE) at this link: Computer Science Engineering (CSE)
119 docs|30 tests

Top Courses for Computer Science Engineering (CSE)

FAQs on Functions in C-2 - Programming and Data Structures - Computer Science Engineering (CSE)

1. What are the different types of functions in C-2 GATE?
Ans. In C-2 GATE, there are three types of functions: library functions, user-defined functions, and recursive functions. Library functions are pre-defined functions provided by the C library, user-defined functions are created by the programmer to perform specific tasks, and recursive functions are functions that call themselves.
2. How do library functions differ from user-defined functions in C-2 GATE?
Ans. Library functions are pre-defined functions provided by the C library, while user-defined functions are created by the programmer. Library functions are already implemented and can be directly used in the program, whereas user-defined functions need to be defined and implemented by the programmer.
3. What is the purpose of recursive functions in C-2 GATE?
Ans. Recursive functions in C-2 GATE are used when a function calls itself to solve a problem. They are particularly useful for solving problems that can be divided into smaller sub-problems. Recursive functions make the code more concise and elegant, but they may consume more memory and time compared to iterative solutions.
4. Can a function in C-2 GATE return multiple values?
Ans. No, a function in C-2 GATE can only return a single value. However, you can use pointers or pass variables by reference to modify multiple values within a function. By passing the address of the variables to the function, you can modify their values directly.
5. How are function prototypes used in C-2 GATE?
Ans. Function prototypes in C-2 GATE are used to declare the function before it is defined or used in the program. They provide information about the function's return type, name, and parameters. Function prototypes help the compiler to verify the correctness of function calls and catch any potential errors during compilation.
119 docs|30 tests
Download as PDF
Explore Courses for Computer Science Engineering (CSE) exam

Top Courses for Computer Science Engineering (CSE)

Signup for Free!
Signup to see your scores go up within 7 days! Learn & Practice with 1000+ FREE Notes, Videos & Tests.
10M+ students study on EduRev
Related Searches

Viva Questions

,

practice quizzes

,

Functions in C-2 | Programming and Data Structures - Computer Science Engineering (CSE)

,

MCQs

,

Summary

,

ppt

,

Objective type Questions

,

Previous Year Questions with Solutions

,

mock tests for examination

,

Exam

,

Functions in C-2 | Programming and Data Structures - Computer Science Engineering (CSE)

,

Functions in C-2 | Programming and Data Structures - Computer Science Engineering (CSE)

,

Sample Paper

,

shortcuts and tricks

,

Extra Questions

,

study material

,

video lectures

,

Semester Notes

,

Free

,

Important questions

,

pdf

,

past year papers

;