Menu
CoddyTech

C Basics Interview Questions

The basics from campus placements and first rounds: building a program, data types, storage classes and functions.

15 questions
  1. What is C, and why is it still used?

    C is a small, compiled, statically typed procedural language with direct access to memory through pointers. It runs kernels, embedded firmware, databases and language runtimes, where speed and predictability matter, and has no garbage collector, exceptions or bounds checking.

    Follow-up: is C object oriented? No; structs and function pointers can imitate objects, but there are no classes.

  2. What are the stages of compiling a C program?

    Four stages: preprocessing (gcc -E expands #include and macros), compilation (gcc -S turns C into assembly), assembly (gcc -c makes an object file) and linking (object files and libraries into an executable).

    "Undefined reference to sqrt" is a linker error: math.h declared the function, so link the library with -lm. On musl (this page's runner) the math functions live in libc itself.

  3. What are the basic data types in C and their sizes?

    char, short, int, long, long long, float, double, long double, and _Bool (C99). The standard fixes only minimum ranges and sizeof(char) == 1; actual sizes depend on the platform.

    C
    #include <stdio.h>
    
    int main(void) {
        printf("char:      %zu\n", sizeof(char));
        printf("short:     %zu\n", sizeof(short));
        printf("int:       %zu\n", sizeof(int));
        printf("long:      %zu\n", sizeof(long));
        printf("long long: %zu\n", sizeof(long long));
        printf("float:     %zu\n", sizeof(float));
        printf("double:    %zu\n", sizeof(double));
        printf("pointer:   %zu\n", sizeof(void *));
        return 0;
    }

    Here long is 8 bytes; on 64-bit Windows it is 4. When width matters, use int32_t and int64_t. See C data types.

  4. What is the difference between a declaration and a definition in C?

    A declaration gives a name and its type; a definition also creates the thing (storage for a variable, the body of a function). Declare as often as you like, define once in the whole program.

    extern int count;          /* declaration: count lives in another file */
    int count = 0;             /* definition: storage is allocated here */
    
    int add(int a, int b);     /* declaration (prototype) */
    int add(int a, int b) {    /* definition */
        return a + b;
    }
    

    So declarations go in headers; a global defined in a header gives "multiple definition" link errors.

  5. What are the storage classes in C?

    A storage class sets a variable's lifetime, scope and linkage: auto, register, static and extern, plus _Thread_local since C11. auto (the default for locals) lives for the block and starts indeterminate; register is the same but its address cannot be taken. A static local lives for the whole program and starts at 0; a file-level static is also limited to its file. extern declares an object defined elsewhere.

  6. What does the static keyword do in C?

    Inside a function, static makes a local keep its value between calls, initialized once. At file level it gives internal linkage, so other files cannot see the name.

    C
    #include <stdio.h>
    
    static int calls_total = 0;   /* visible only in this file */
    
    int next_id(void) {
        static int id = 100;      /* initialized once, not on every call */
        calls_total++;
        return id++;
    }
    
    int main(void) {
        printf("%d\n", next_id());
        printf("%d\n", next_id());
        printf("%d\n", next_id());
        printf("calls: %d\n", calls_total);
        return 0;
    }

    It prints 100, 101, 102 and calls: 3.

  7. Does C support call by reference?

    No. C passes every argument by value. To let a function change the caller's variable, pass its address; the pointer itself is still copied.

    C
    #include <stdio.h>
    
    void swap_copy(int a, int b) { int t = a; a = b; b = t; }
    
    void swap_ptr(int *a, int *b) { int t = *a; *a = *b; *b = t; }
    
    int main(void) {
        int x = 1, y = 2;
        swap_copy(x, y);
        printf("after swap_copy: %d %d\n", x, y);
        swap_ptr(&x, &y);
        printf("after swap_ptr:  %d %d\n", x, y);
        return 0;
    }

    swap_copy leaves 1 2; swap_ptr gives 2 1. An array argument decays to a pointer, and that pointer is copied too.

  8. What is recursion? Write a recursive factorial in C.

    Recursion is a function calling itself on a smaller input until a base case it answers directly. Each call takes a stack frame, so very deep recursion overflows the stack.

    C
    #include <stdio.h>
    
    unsigned long long factorial(unsigned int n) {
        if (n <= 1) return 1;          /* base case */
        return n * factorial(n - 1);   /* smaller problem */
    }
    
    int main(void) {
        for (unsigned int i = 0; i <= 20; i += 5)
            printf("%u! = %llu\n", i, factorial(i));
        return 0;
    }

    20! is the largest factorial that fits in 64 unsigned bits. See the recursion visualizer.

    Practice it: Factorial, Fibonacci Number

  9. What is a header file, and what is the difference between #include <file.h> and #include "file.h"?

    A header holds declarations shared by several .c files, and #include pastes its text in. <stdio.h> searches the system directories; "list.h" searches the current file's directory first (the exact order is implementation-defined; this is GCC and Clang). Headers should define no functions or globals except static inline functions, and need an include guard.

  10. What do -7 / 2 and -7 % 2 give in C?

    C
    #include <stdio.h>
    
    int main(void) {
        printf("%d %d %d %d\n", 7 / 2, -7 / 2, 7 % 2, -7 % 2);
        return 0;
    }

    It prints 3 -3 1 -1. Since C99, integer division truncates toward zero, and % takes the sign of the left operand so that (a / b) * b + a % b == a. So test for odd with n % 2 != 0; n % 2 == 1 is false for negative odd numbers.

    Practice it: Count Even Numbers

  11. How do i++ and ++i differ when you assign the result?

    C
    #include <stdio.h>
    
    int main(void) {
        int i = 5;
        int a = i++;
        int b = ++i;
        printf("%d %d %d\n", a, b, i);
        return 0;
    }

    It prints 5 7 7. i++ yields the old value and then increments, so a is 5; ++i increments first, so i and b are 7. Each statement modifies i once, so this is defined; i++ + ++i in one expression is undefined behavior.

  12. What is type casting in C, and what are implicit conversions?

    A cast converts a value explicitly with (type) value. Implicit conversions convert the smaller operand to the larger type, and promote char and short to int before arithmetic.

    C
    #include <stdio.h>
    
    int main(void) {
        int a = 7, b = 2;
        double wrong = a / b;            /* int division first, then converted */
        double right = (double) a / b;   /* a becomes double, so b does too */
        int truncated = (int) 3.99;      /* casting to int drops the fraction */
        printf("%.1f %.1f %d\n", wrong, right, truncated);
        return 0;
    }

    It prints 3.0 3.5 3: a / b divides as ints first. Converting a double that does not fit, as in (int) 1e10, is undefined behavior, not a wrap.

  13. What are argc and argv in main?

    argc is the number of command-line arguments and argv the array of strings holding them; argv[0] is normally the program name and argv[argc] is a null pointer.

    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, char *argv[]) {
        if (argc < 2) {
            fprintf(stderr, "usage: %s NUMBER\n", argv[0]);
            return 1;
        }
        int n = atoi(argv[1]);   /* arguments always arrive as strings */
        printf("%d squared is %d\n", n, n * n);
        return 0;
    }
    

    ./square 7 prints 7 squared is 49. Prefer strtol to atoi, which cannot report bad input. See command-line arguments.

  14. How do you write to and read from a file in C?

    fopen returns a FILE * or NULL; write with fprintf, read with fgets, then fclose. Mode "w" creates or truncates, "a" appends, "r" fails if the file is missing.

    C
    #include <stdio.h>
    
    int main(void) {
        FILE *fp = fopen("notes.txt", "w");
        if (fp == NULL) { perror("fopen"); return 1; }
        fprintf(fp, "line %d\n", 1);
        fputs("line 2\n", fp);
        fclose(fp);
    
        fp = fopen("notes.txt", "r");
        if (fp == NULL) { perror("fopen"); return 1; }
        char buf[64];
        while (fgets(buf, sizeof buf, fp) != NULL)
            printf("read: %s", buf);
        fclose(fp);
        return 0;
    }

    It prints read: line 1 and read: line 2. Loop on fgets, not feof, which turns true only after a read has failed. See file handling.

  15. Write a C program to check whether a number is prime.

    Test divisors up to √n, since a divisor above √n pairs with one below it; skip even numbers after 2. That is O(√n).

    C
    #include <stdio.h>
    #include <stdbool.h>
    
    bool is_prime(int n) {
        if (n < 2) return false;
        if (n % 2 == 0) return n == 2;
        for (int d = 3; d <= n / d; d += 2)
            if (n % d == 0) return false;
        return true;
    }
    
    int main(void) {
        for (int n = 0; n <= 30; n++)
            if (is_prime(n)) printf("%d ", n);
        printf("\n");
        printf("97: %s, 91: %s\n", is_prime(97) ? "prime" : "not prime",
               is_prime(91) ? "prime" : "not prime");
        return 0;
    }

    It prints the primes up to 30 and 97: prime, 91: not prime. The loop tests d <= n / d because d * d can overflow a signed int, which is undefined behavior.

    Practice it: Check Prime Number

Coddy programming languages illustration

Learn to code with Coddy

Get started