Interview Questions and Notes

Coding, Programming, Software interview questions, examples and references


Last Updated: February 04, 2020 by Pepe Sandoval



Want to show support?

If you find the information in this page useful and want to show your support, you can make a donation

Use PayPal

This will help me create more stuff and fix the existent content...


Index

General Computers Architecture and Digital Hardware Questions

Programming

Linux & Operating Systems Questions

Embedded Systems & RTOS Questions

Validation, Verification, Testing...

Other Questions

External references to practice coding

Codility
Hacker Rank

General Computers Architecture and Digital Hardware Questions

  1. Do you know the Harvard and Von Neumann architectures? What is its main difference?

  2. Do you know about the RISC and CISC instruction set architectures (ISA)? What are some of their (main) characteristics?

  3. Do you know about the memory hierarchy? Why do we need it? Why not just use fast memory (cache)?

  4. What are the most common stages of execution of an instruction in a simple RISC architecture?

  5. In processors context What's Pipeline? And why do we use it? Why not implement as a unicycle?

  6. What is cache coherence

  7. Can you draw a CPU architecture diagram or its main blocks?

  8. In computer architecture what defines whether a system is a 32-bits or 64-bits system?

    • a) Register Size
    • b) Memory data buses
    • c) Memory address buses

Programing

C General Programing Questions

  1. Which of the following is NOT a reserved word in C?

    • a) sizeof
    • b) try
    • c) signed
    • d) register
  2. According with the following code, which is the output after its execution?

    #define EOF_INT_SHIFT 4
    printf("%x\r\n", 1<<EOF_INT_SHIFT + 0x02);
  • a) 12
  • b) 34
  • c) 40
  • d) 18
  1. According with the following code, which is the output after its execution?

#include <stdio.h> #define EOF_INT 0x0020

int main(int argc, char *argv[]) { unsigned char int_status = 0x001F; unsigned char int_event = 0;

  if(int_status & EOF_INT != 0)
    int_event |= EOF_INT;
  else
    int_event &= ~EOF_INT;

  printf("%d\n", int_event);

}

  • a) 32
  • b) 20
  • c) 0
  1. The result of the following operation: !(0 || !1 && 0 || 3 && 1) is?

    • a) true
    • b) false
    • c) Invalid operation
    • d) Compiler error
  2. What would be the result of compiling black.c and blue.c files separately and then calling the linker to combine them in a single program
    linker problem

    • a) Compilation error
    • d) Link error
    • c) The program may be created (depends on linker)
  3. According with the following code, which is the output after its execution?

#include <stdio.h> #define MULTIPLY(x,y) (x*y)

int main(int argc, char *argv[]) { int a = 2; int b = 4; int c = 5; printf("%d\n", MULTIPLY(a+b, c++)); }

  • a) 26
  • b) 36
  • c) 23
  • d) 22
  1. According with the following code, which is the output after its execution?

#include <stdio.h> #define DEBUG 0

int main(int argc, char *argv[]) { #ifdef DEBUG float x = 3/2; printf("%f\n",x); #else printf("DEBUG OFF\n"); #endif }

  • a) 1.5000
  • b) DEBUG OFF
  • c) 1.000
  • d) Invalid code
  1. If you keep incrementing a variable, will this variable become negative at some point?
  • a) true
  • b) false
  • c) Depends on _________
  1. According with the following code, which is the output after its execution?

#include <stdio.h>

int main(int argc, char *argv[]) { unsigned x[10] = {0,0,0,0,0,0,0,0,0,0}; unsigned * px = x; printf("%d, %d\n",sizeof(x), sizeof(px)); }

  • a) Depends on _________
  • b) 40, 4
  • c) 10, 4
  • d) 10, 10
  • e) 40, 40
  • f) 4, 4
  • g) Compilation error
  1. How many times does the following loop run? for(x=0; x=3; x++)
  • a) Three times
  • b) Four Times
  • c) Never
  • d) Forever
  1. Which is the output after running the following code?

#include <stdio.h>

int main(int argc, char *argv[]) { int x; while(x < 100) { printf("%d, ",x); x++; } }

  • a) 0, 1, 2, 3, ... 99,
  • b) 0, 1, 2, 3, ... 100,
  • c) Undefined
  1. According with the following code, which is the output after its execution? Semicolon at line 5 is not a typing error, it is part of the C code.
    #include <stdio.h>
    
    int main(int argc, char *argv[]) {
      int i = 0, x = 0;
      for(i=0; i<10; i++);
      {
        x++;
      }
      printf("%d\n", x);
    }

  • a) 0
  • b) 1
  • c) 10
  • d) Compilation Error
  1. Which is the output after running the following code?
    #include <stdio.h>
    
    int main(int argc, char *argv[]) {
      int i = 0;
      while(i++<10);
      printf("%d\n", i);
    }

  • a) 9
  • b) 10
  • c) 11
  • d) Compilation Error
  1. Which is the output after running the following code?
    #include <stdio.h>
    
    int main(int argc, char *argv[]) {
      int i = 0;
      int x = 0;
      for(i=0; i<10; i++){
        if((i>2) && (i<5))
          continue;
        if(i==8)
          break;
        x++;
      }
      printf("%d, %d\n",x,i);
    }

  • a) 10, 10
  • b) 10, 8
  • c) 8, 8
  • d) 6, 8
  1. What does the following code mean: for(;;);
  • a) Invalid Code
  • b) Infinite loop
  • c) Ignored by the compiler
  • c) Compiler error
  1. According with the following code?
    #include <stdio.h>
    
    int main(int argc, char *argv[]) {
      int x = 1;
      int* p = &x;
      *p = 2;
      *p++ = 10;
    
      printf("%d\n",x);
    }

  1. 15-1. What is the value of x printed?

    • a) 2
    • b) 3
    • c) 10
    • d) 11
  2. 15-2. Does the pointer p points to a variable defined in main?

    • b) Yes, points to the variable x
    • b) No
  3. What is a macro in C? Can you provide an example?

  4. How would you define a type using typedef? What's the difference between defining a type using typedef and with a macro, using #define?

  5. Which is the output after executing the following code?

    #include <stdio.h>
    
    int main(int argc, char *argv[]) {
      int a = 0;
      int b = 1;
      int c = 2;
      c = (a > b) ? a : b++;
      printf("%d %d %d\n", a, b, c);
    }

  • a) 0 2 1
  • b) 2 0 2
  • c) 0 2 2
  • d) Invalid code
  1. Assuming a compiler that supports C99 and according with the following code, which is the output after its execution?
    #include <stdio.h>
    
    int main(int argc, char *argv[]) {
      // Struct Definition
      struct node {
                      int a;
                      int b;
                      int c;
                  };
    
      // Structs declarations
      struct node s = { 5, 13, 6 };
      struct node z = { b:14, c:2, a:7 };
    
      // Pointers
      struct node *pt = &s;
      struct node *ptz = &z;
    
      printf("pt=%d ptz=%d\n" , * (int*)pt , * (int*)ptz );
    }

  • a) pt=13 ptz=14
  • b) pt=5 ptz=7
  • c) pt=5 ptz=14
  • d) Invalid Code
  • e) Compilation Error
  1. What is the difference, related to memory, between a local variable, global variable and a variable allocated with malloc (dynamic)?

  2. Which operator is used to access a member of a structure referenced by a pointer?

  • a) *
  • b) ->
  • c) >>
  • d) &
  1. Assuming a 32-bit system where int variables are 4-bytes long and not specificing any pragmas, which is the output after the execution of the following code?
    #include <stdio.h>
    
    int main(int argc, char *argv[]) {
        typedef struct _SMX_ {
          int x;
          char a;
          int y;
          char b;
          int z;
          char c;
        } SMX, * P_SMX;
    
        typedef struct _BAS_ {
          int x;
          int y;
          int z;
          char a;
          char b;
          char c;
        } BAS, * P_BAS;
    
        printf("%d %d\n", sizeof (SMX), sizeof (BAS));
    }

  • a) 15 15
  • b) 6 6
  • c) 24 16 . Due to not specifying it declaration order will cause more memory to be used.
  • d) 16 16
  • e) Compile error, becasue the way sizeof is used on custom types
  1. Which character is used to terminate the strings in C?
  • a) .
  • b) \x
  • c) \END
  • d) \0
  1. Which is the output after executing the following code?
    #include <stdio.h>
    
    int main(int argc, char *argv[]) {
      int arr[] = {8, 7, 6, 5, 4, 3, 2};
      printf("%d\n" , *(arr+2)+1 );
    }

  • a) 7
  • b) 8
  • c) 6
  • d) 5
  1. According with the following code, which is the output after its execution?
    #include <stdio.h>
    
    void f1(int *, int);
    void f2(int *, int);
    void(*p[2]) (int*, int);
    
    int main(int argc, char *argv[]) {
        int a = 3;
        int b = 5;
        p[0] = f1;
        p[1] = f2;
    
        p[0](&a , b);
        printf(" %d %d " , a ,b);
    
        p[1](&b , a);
        printf(" %d %d " , a ,b);
    }

void f1(int* p , int q){ int tmp; tmp = *p; *p = q; q = tmp; }

void f2(int* p , int q){ int tmp; tmp = *p; *p = q; q = tmp; }

  • a) 5 3 5 3
  • b) 3 5 3 5
  • c) 5 5 5 5
  • d) 3 3 3 3
  1. Which is the output of the following program?
    #include <stdio.h>
    
    int counter (int i) {
        static int count = 0;
        count = count + i;
        return (count);
    }
    
    int main(int argc, char *argv[]) {
        int i , j;
        for (i = 0; i <= 5; i++)
        j = counter(i);
        printf("%d\n", j);
    }

  • a) 10
  • b) 15
  • c) 5
  • d) 4
  1. What's the return value of the following function calling it with v = 13?

#include <stdio.h>

int fn(int v) { if (v == 1 || v == 0) return 1; if (v%2 == 0) return fn(v/2) + 2; else return fn(v-1) + 3; }

  • a) 13
  • b) 10
  • c) 16
  • d) Invalid Code
  • e) Runtime error
  1. Assuming a 32-bit architecture which of the following data structures uses less memory?
  • a) struct mystruct { int i; float f; int b; };
  • b) union myunion { unsigned int ui; float f; char c[4]; };
  • c) char array[10];
  1. Which code represents a call to a function which is located at the address 0 of the system memory?
  • a) (*(void(*)(0)))();
  • b) (*(void(*)()0))();
  • c) (*(void(*)())0)();
  1. According with the following code, which is the output after its execution?
    #include <stdio.h>
    
    int main(int argc, char *argv[]) {
      int x[] = {3, 5, 2, 4};
      int y = 0;
      int i = 1;
    
      y = i + x[i++];
      x[i] = y + i++;
    
      printf("%d ",y);
      for(i=0; i<4; i++) { printf("%d ",x[i]); }
    }

  • a) Undefined
  • b) 7 3 5 9 4
  • c) 6 3 5 8 4
  • d) 7 3 5 2 9
  1. What does the following declaration mean in C? int func();
  • a) func is a function with any number and type of arguments.
  • b) func is a function with no arguments.
  • c) func would receive a single int argument as default.
  • d) Invalid function declaration
  1. What does the volatile modifer means?

  2. What is the build process of a C program?


C Coding Problems

  1. Write a function in C that calculates the factorial of a given number. Function takes as input an integer and returns the factorial of that number

#include <stdio.h>

int factorial(int);

int main(int argc, char *argv[]) { printf("Factorial of 5 = %d\n", factorial(5)); return 0; }

// F(n) = nF(n-1) ; if n == 0 then return 1 int factorial(int n) { if (n == 0) return 1; else return (nfactorial(n-1)); }

  1. Write a function in C that calculates the Fibonacci series ([0, 1, 1, 2, 3, 5, 8, 13, 21]). Function takes as input an integer representing the position of the Fibonacci series and returns the corresponding value of Fibonacci Serie for that posistion

#include <stdio.h>

int fibonacci(int);

int main(int argc, char *argv[]) { printf("Fibb of 2 = %d\n", fibonacci(2)); return 0; }

// F(n) = F(n-1) + F(n-2) , F0 = 0, F1 = 1 ; if n<2 then return n int fibonacci(int n) { if (n < 2) return n; else return (fibonacci(n-1) + fibonacci(n-2)); }

  1. Write a function in C that performs bubble sort search in an array. Function takes as input the array and size and sorts it

#include <stdio.h>

void bubble_sort(int*, int);

#define ARRAY_SIZE 10 int test_array[ARRAY_SIZE] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0};

int main(int argc, char *argv[]) { bubble_sort(test_array, ARRAY_SIZE); return 0; }

// Most common implementation with two loops // Most inner loops through array and swaps elements // Second loop repeats until no more swaps are needed void bubble_sort(int* array, int len) { int temp = 0; char swap = 0; do { swap = 0; for(int i = 1; i < len; i++) { if(array[i-1] > array[i]) { temp = array[i]; array[i] = array[i-1]; array[i-1] = temp; swap = 1; } } } while(swap != 0); }

  1. Write a function in C that inverts the values of an array. Function takes as input an array and modifies it accordingly

#include <stdio.h> void invert_array(int*, int);

#define ARRAY_SIZE 9 int test_array[ARRAY_SIZE] = {9, 8, 7, 6, 5, 4, 3, 2, 1};

int main(int argc, char *argv[]) { invert_array(test_array, ARRAY_SIZE); return 0; }

void invert_array(int* array, int len) { int temp = 0; for(int i = 0; i < len/2; i++) { temp = array[len-i-1]; array[len-i-1] = array[i]; array[i] = temp; } }

  1. Write a function in C that counts the number of bits set to 1 in a variable. Function takes as input the variable and returns a number representing the number of bits set

#include <stdio.h> unsigned int count_bits(unsigned char);

int main(int argc, char *argv[]) { unsigned char test_var = 0xA5; printf("# bits set in 0x%x -> %d \n", test_var, count_bits(test_var)); return 0; }

unsigned int count_bits(unsigned char var) { unsigned int count = 0; while(var > 0) { if(var & 0x01) { count++; } var >>= 1; } return count; }

  1. Write a function to invert the order of the bits in a variable. Function must receive a pointer to the variable and the change must occur in the space of memory pointed by that argument.

Invert bits

  1. Using C syntax declare a function that returns the sum of two integers, then declare a function pointer that points to that function and call the function using the pointer to the function. Can we call the function using the following syntax (*pFunc)(1, 2); ?

#include <stdio.h>

int sum_integers(int, int);

// Option A: Declare as global variable and init function pointer in declaration int (*pFunc)(int, int) = sum_integers;

// Option B: Define a function pointer type typedef int (* my_func_ptr_t)(int, int);

int main(int argc, char *argv[]) {

 // Declare function pointer using defined type and init the pointer
 my_func_ptr_t pFuncLocal;
 pFuncLocal = sum_integers;

 // All calls are equivalent and valid
 printf("Call function explicitly: %d\n", sum_integers(1 , 2));

 printf("Call using function pointer pFunc: %d\n", pFunc(1 , 2));
 printf("Call using function pointer pFuncLocal: %d\n", pFuncLocal(1 , 2));

 printf("Call dereferencing pFunc: %d\n", (*pFunc)(1 , 2));
 printf("Call dereferencing pFuncLocal: %d\n", (*pFuncLocal)(1 , 2));

 printf("Call casting function address without &: %d\n"  , ((int (*)(int, int)) (sum_integers))(1, 2));
 printf("Call casting function address with &: %d\n", ((int (*)(int, int)) (&sum_integers))(1, 2));
 printf("Call casting function address and dereferencing without &: %d\n", (*((int (*)(int, int)) (sum_integers)))(1, 2));
 printf("Call casting function address and dereferencing with &: %d\n", (*((int (*)(int, int)) (&sum_integers)))(1, 2));

 printf("Call casting function address using defined type without &: %d\n"  , ((my_func_ptr_t) (sum_integers))(1, 2));
 printf("Call casting function address using defined type with &: %d\n", ((my_func_ptr_t) (&sum_integers))(1, 2));
 printf("Call casting function address using defined type and dereferencing without &: %d\n", (*((my_func_ptr_t) (sum_integers)))(1, 2));
 printf("Call casting function address using defined type and dereferencing with &: %d\n", (*((my_func_ptr_t) (&sum_integers)))(1, 2));

 // All these expressions return the address of the function
 printf("Address stored in pFuncLocal: 0x%llx\n", (long long int) (pFuncLocal));
 printf("Address stored in pFunc: 0x%llx\n", (long long int) (pFunc));
 printf("Get address of sum_integers function without using &: 0x%llx\n", (long long int) (sum_integers));
 printf("Get address of sum_integers function using & : 0x%llx\n", (long long int) (&sum_integers));

 return 0;

}

int sum_integers(int a, int b) { return (a + b); }

  1. Write a function that detects endianness. For example it returns 1 if running on a Little-Endian architecture and 0 when running on a Big-Endian one.

#include <stdio.h> unsigned char is_little_endian(void);

int main(int argc, char *argv[]) { printf("is little endian: %d\n", is_little_endian()); return 0; }

unsigned char is_little_endian(void) { unsigned int x = 1; unsigned char* y = (char*) (&x); return ((*y) == 1); }

  1. Write a function to convert a 32-bit int variable from Little-Endian to Big-Endian. Function must receive a pointer to the int that we would like to change and the change must occur in the space of memory pointed by that argument.
    Hint: little endian -> least significant first ; big-endian -> most significant first

Endianness

  1. Write a function to add matrixes. Function receives as paramaters pointers to the matrixes, the number of rows and colums and should work for any matrix size. The function must return a pointer to the beginning of the resulting matrix. Global variables for any of the matrixes can be used

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

#define MATX_ROWS (3) #define MATX_COLS (3)

#define MATY_ROWS (3) #define MATY_COLS (3)

int matX[][MATX_COLS] = { { 0 , 1 , 2 }, { 3 , 4 , 5 }, { 6 , 7 , 8 } };

int matY[][MATY_COLS] = { { 8 , 7 , 6 }, { 5 , 4 , 3 }, { 2 , 1 , 0 } };

int* sum_mat(int* matA, int* matB, int rows, int cols);

int main(int argc, char argv[]) { int matR = sum_mat(&matX[0][0], &matY[0][0], MATX_ROWS, MATY_COLS); // TODO: free memory to avoid memory leaks -> free() return 0; }

int* sum_mat(int* matA, int* matB, int rows, int cols) { int* matR = (int*) malloc(sizeof(int)rowscols);

  for (int r = 0; r < rows; r++) {
    for (int c = 0; c < cols; c++) {
      *(matR + c + r*cols) = *(matA + c + r*cols) + *(matB + c + r*cols);
    }
  }

  return matR;

}

  1. Write a function to multiply matrixes. Function receives as paramaters pointers to the matrixes, the number of rows and colums of each matrix and should check if multiplication is possible. The function must return a pointer to the beginning of the resulting matrix. Global variables for any of the matrixes can be used

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

#define ROWS_A (2) //<-----------------| #define COLS_A (3) // <----| |-> outers // |-> inners | #define ROWS_B (3) // <----| | #define COLS_B (4) //<-----------------|

int matrixA[][COLS_A] = { { 3 , 4 , 2 }, { 1 , 2 , 3 } };

int matrixB[][COLS_B] = { { 13, 9, 7, 15 }, { 8, 7, 4, 6 }, { 6, 4, 0, 3 } };

// Option 1: Use only pointers int* mul_mat_pointers(int* matA, unsigned int rowsA, unsigned int colsA, int* matB, unsigned int rowsB, unsigned int colsB) { int* matR = NULL;

  // Inners should match to be able to perfom multiplication
  if(colsA == rowsB) {
    // Outers determine size of resulting matrix
    matR = (int*) malloc(sizeof(int) * rowsA * colsB);

    for (int r = 0; r < rowsA; r++) {
      for (int c = 0; c < colsB; c++) {
          int sum = 0;
          // Inners determine number of multiplications needed, use colsA or rowsB it's the same
          for(int i = 0; i < colsA; i++) {
              // For pointer iteration always multiply by 'columns' to access elements
              sum += ((*(matA + r*colsA + i)) * (*(matB + i*colsB + c)));
          }
          // Again multiply by 'columns' to access element
          *(matR + r*colsB + c) = sum;
      }
    }
  }

  return matR;

}

// Option 2: Use indexes int matrixR[ROWS_A][COLS_B] = {}; int* mul_mat_indexes(int matA[ROWS_A][COLS_A], int matB[ROWS_B][COLS_B]) {

  // Malloc Matrix if you want to use dynamic memory
  //int** matrixR = malloc(ROWS_A * sizeof(int**)); for(int i = 0; i < ROWS_A; i++) matrixR[i] = malloc(COLS_B*sizeof(int*));

  if(COLS_A == ROWS_B) {

    for (int r = 0; r < ROWS_A; r++) {
      for (int c = 0; c < COLS_B; c++) {
          int sum = 0;
          // Inners determine number of multiplications needed, use COLS_A or ROWS_B it's the same
          for(int i = 0; i < COLS_A; i++) {
              sum += (matA[r][i] * matB[i][c]);
          }
          matrixR[r][c] = sum;
      }
    }
  }
  return &matrixR[0][0];

}

int main(int argc, char argv[]) { int matR = mul_mat_pointers(&matrixA[0][0], ROWS_A, COLS_A, &matrixB[0][0], ROWS_B, COLS_B); ////or //int* matR = mul_mat_indexes(matrixA, matrixB);

  // TODO: free memory to avoid memory leaks -> free()
  return 0;

}

  1. Implement an interface for a Stack (LIFO) data structure in C, it must consist of at least 2 functions to push and pop data from the Stack

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

// For stack use only tail/top pointer and hold reference to prev node // on init set pointer to NULL, on push move tail, // on pop move tail to prev (tail->prev) typedef struct stack_node { unsigned int data; struct stack_node* prev; } stack_node_t;

stack_node_t* tail = NULL;

unsigned int stack_is_empty(void) { return (tail == NULL); }

void stack_push(unsigned int dat) { stack_node_t* newNode = (stack_node_t*) malloc(sizeof(stack_node_t));

  // Test for malloc return: if(newNode != NULL)
  newNode->data = dat;
  newNode->prev = tail;
  tail = newNode;

}

signed int stack_pop(void) { signed int dat = -1; stack_node_t* toFreeNode = NULL; if(!stack_is_empty()) { toFreeNode = tail; dat = toFreeNode->data; tail = tail->prev; free(toFreeNode); }

  return dat;

}

int main(int argc, char *argv[]) { printf("Stack Test!\n");

  stack_push(3);
  stack_push(2);
  stack_push(1);

  unsigned int a = 0;
  a = stack_pop();
  a = stack_pop();
  a = stack_pop();

  return a;

}

  1. Implement an interface for a Queue (FIFO) data structure in C, it must consist of at least 2 functions to add and get data from the Queue

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

// For queue use tail and head pointers and hold reference to next node // on init set both, on add move tail, // on get move head and check if tails needs to be set to NULL typedef struct queue_node { unsigned int data; struct queue_node* next; } queue_node_t;

queue_node_t* head = NULL; queue_node_t* tail = NULL;

unsigned int queue_is_empty(void) { return ((head == NULL) && (tail == NULL)); }

void queue_add(unsigned int dat) { queue_node_t* newNode = (queue_node_t*) malloc(sizeof(queue_node_t));

  // Test for malloc return: if(newNode != NULL)
  newNode->data = dat;
  if(!queue_is_empty()) {
     newNode->next = NULL; // Equivalent to: newNode->next = tail->next;
     tail->next = newNode;
     tail = newNode;
  } else {
     newNode->next = NULL;
     tail = newNode;
     head = newNode;
  }

}

signed int queue_get(void) { signed int dat = -1; queue_node_t* toFreeNode = NULL; if(!queue_is_empty()) { toFreeNode = head; dat = toFreeNode->data; head = head->next; if(head == NULL) { tail = NULL; } free(toFreeNode); }

  return dat;

}

int main(int argc, char *argv[]) { printf("Queue Test!\n");

  queue_add(3);
  queue_add(2);
  queue_add(1);

  unsigned int a = 0;
  a = queue_get();
  a = queue_get();
  a = queue_get();

  return a;

}

  1. Implement an interface for a Linked List data structure in C, it must consist of at least 2 functions: 1) append which adds elements at the end of the list, 2) get which removes an element from certain index data from the Linked List and returns the value stored in that index

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

typedef struct linked_list_node { unsigned int data; struct linked_list_node* next; struct linked_list_node* prev; } linked_list_node_t;

linked_list_node_t* head = NULL; linked_list_node_t* tail = NULL; unsigned int size = 0;

unsigned int linked_list_is_empty(void) { return (size == 0); }

void linked_list_append(unsigned int dat) { linked_list_node_t* newNode = (linked_list_node_t*) malloc(sizeof(linked_list_node_t)); // Test for malloc return if(newNode != NULL) newNode->data = dat; if(!linked_list_is_empty()) { newNode->prev = tail; newNode->next = tail->next; // should be null tail->next = newNode; tail = newNode; } else { newNode->prev = NULL; newNode->next = NULL; tail = newNode; head = newNode; } size++; }

signed int linked_list_get(unsigned int index) { signed int dat = -1; linked_list_node_t* toFreeNode = NULL; if(!linked_list_is_empty()) { if(index == 0) { toFreeNode = head; head = head->next; head->prev = NULL; } else if (index == (size - 1)) { toFreeNode = tail; tail = tail->prev; tail->next = NULL; } else if(index < size) { linked_list_node_t* search_node = head; while(index != 0) { search_node = search_node->next; index--; } toFreeNode = search_node; } }

  if(toFreeNode != NULL) {
     dat = toFreeNode->data;
     free(toFreeNode);
     size--;
  }

  return dat;

}

int main(int argc, char *argv[]) { printf("linked list test!\n");

  linked_list_append(0);
  linked_list_append(1);
  linked_list_append(3);

  unsigned int a = 0;
  a = linked_list_get(2);
  a = linked_list_get(1);
  a = linked_list_get(0);

  return a;

}


General Object Oriented Programming (OOP) Questions

  1. What is a class? an object? What are its two main components?

  2. What are the main characteristics of OOP (Object Oriented Programming)?

  • Polymorphism: the ability that certain functionality/code can behave differently depending on the context. E.g. the move() method in a animals hierarchy class (all animals move but do it differently)


C++ General Programming Questions

  1. What is the auto reserved word in used for in C++?

  2. In the context of C++ what's a reference? What's the difference between a reference and a pointer

  3. In the context of C++ what are templates? What are they used for?

#include <iostream>

template<typename T> T sum_types(T varA, T varB) { return varA + varB; } int main(int argc, char *argv[]) { std::cout << sum_types<std::string>("10", "11") << std::endl; std::cout << sum_types<unsigned int>(10, 11) << std::endl; }

  1. In the context of C++ what is Operator Overloading? what is it used for?

  2. In the context of C++ what's a virtual function and a pure virtual? What are they used for?

  • Used to implement polymorphism, virtual functions allow to execute different actions depending on the object thats is being referenced (pointed to)
  • When a function is declared with the virtual modifier the code executed when it's called always depends on the object that is being referenced (pointed to), It does NOT matter the type of the pointer or reference used to perform the call, what matters is the object
  • On non-virtual functions the code executed when the function is called depends on the reference or pointer used NOT on the object
  • pure virtual are functions with no implementation that are used to define a common interface for a classes hierarchy, these functions force a derivative class to implement them
  • A class with one or more pure virtual functions is called an abstract class

// Assuming both have the function 'print' implemented (Deriv class overwriting it) // if 'print' is 'virtual' then the 'print' function defined in 'DerivClass' is called // if 'print' is 'non-virtual' then the 'print' function defined in 'BaseClass' is called BasePtr->print();


C++ Coding

  1. Write a functions that swaps two values? Function must use C++ references.

  1. Define the following class hierachy in C++:
  • create a class Person which has the attributes name (string) and age (unsigned int), it's constructor must receive these as parametert to init attributes. This class has a method called print that prints name and age of the person
  • create a class Student that inherits from Person to include an attribute school (string), it's constructor inits this attribute and calls base class to init the other attributes. Student class overwrites the base class print method to now print name, age and school of the student
  • Overload operator ++ in the class Person to increment the age atrribute when called. E.g. the code Person p1("Jose", "27"); ++p1; should run and make age attribute of p1 equals to 28
  • Create a std::shared_ptr; of type Person that points to a newly created instance of Student (use the operator new to create this instance) and call the function print using this pointer

    // file: person.cpp
    #include "person.hpp"

Person::Person(std::string name, unsigned int age) {
    this->name = name;
    this->age = age;
}

void Person::print(void) {
    std::cout << "Person name: " << this->name << " age: " << this->age << std::endl;
}

Person& Person::operator++(void) {
    (this->age)++;
    return (*this);
}

    // file: student.hpp
    #include <iostream>
    #include "person.hpp"

class Student : public Person {
    public:
        Student(std::string name, unsigned int age, std::string school);
        virtual void print(void);
    private:
        std::string school;
};

    // file: student.cpp
    #include "student.hpp"

// Base class constructor (Person in this case) must be called from the initialization list
Student::Student(std::string name, unsigned int age, std::string school) : Person(name, age) {
    this->school = school;
}

void Student::print(void) {
    Person::print();
    std::cout << "Student school: " << this->school << std::endl;
}

    // file: main.cpp
    // g++ -std=c++11 -Wall ./main.cpp ./person.cpp ./student.cpp ./person.hpp ./student.hpp -o test
    #include <iostream>
    #include <memory>
    #include "student.hpp"

int main(int argc, char *argv[]) {
    std::shared_ptr<Person> personPtr (new Student ("Jose M", 27, "edX"));
    ++(*personPtr);
    personPtr->print(); // This calls the 'print' function from 'Student' becasue 'print' is a virtual function
}


Python General Programming Questions

  1. In Python what is the difference between lists, tuples and sets?

  2. Python is a compiled or interpreted language and what this means?

  3. What is a decorator in Python?

  4. What is an anonymous function in Python and how it works?


Python Coding

  1. Write a program in Python that when executed will prompt the user for text input and reply with the correct response as provided in the following table. The program should continue to prompt for input and reply with the appropriate response until an input value is provided that is not valid, i.e. not in the table. Please make all input case insensitive.
input output
Red Green
Green Black
Black Blue
Blue Yellow
Yellow Red
White Black
Purple Green
  1. Write a function in Python that receives as a parameter a string and returns the first character that is repeated in that string, returns None if no character is repeated
  1. Write a function in Python that receives an integer and returns in a list all the divisors of that number
  1. Write a function in Python that receives a list of integers and returns a list of the same size where each element is created by the multiplication of all the other elements of the list received as parameter except for the one in the index you are trying to calculate. So for example given the list [1, 2, 3, 4] it returns [24, 12, 8, 6] because for index 0: it multiples 2x3x4=24 avoiding the value 1, for index 1: 1x3x4=12 avoiding the value 2 and so on...
  1. Write a function in Python that receives a list of integers (positive and negative) and returns the sum of all the two digit numbers in that list so for example given the list [1, 1000, 80, -91] it returns -11 because it's the sum of 80 and -91 (-91+80=-11)
  1. Consider the format HH:MM:SS to define a certain point in time of the day for example 16:11:16 to describe 4:11pm with 16 seconds. A point in time, like this one, is considered "interesting" if it needs 2 or less different digits to represent it so the previous example would be considered "interesting" because it only needs the digits 1 and 6.

    Considering this definition of "interesting", write a function in Python that receives a start (S) and end (T) points in time in the format HH:MM:SS and returns the number of points considered "interesting" between this time interval including both limits (S and T), under the assumption T will always be a later time than (S). So for example given S="22:22:21" and T="22:22:23" as inputs to your function it should return 3 because 22:22:21, 22:22:22 and 22:22:23 are all considered "interesting"


  1. Binary gap within a positive integer N is any maximal sequence of consecutive zeros that is surrounded by ones at both ends in the binary representation of N. For example, number 9 has a binary representation 1001 and contains a binary gap of length 2, numbers 32(100000) and 15 (1111) have no binary gaps, while 545(1000100001) and 529(1000010001) contains two binary gaps: one of length 4 and one of length 3 each

    Considering this definition of "binary gap", write a function that, given a positive integer N, returns the length of its longest binary gap. The function should return 0 if N doesn't contain a binary gap.


  1. A right rotation of an array shifts each element of the array 1 unit to the right and the last element of the array is moved to the first place. For example [3, 8, 9, 7, 6] right rotated 3 times is -> [9, 7, 6, 3, 8]. A left rotation of an array shifts each element of the array 1 unit to the left and the first element of the array is moved to the last place For example [1, 2, 3, 4, 5] left rotated 4 times is -> [5, 1, 2, 3, 4].

    Considering this, write two functions that, given an array A consisting of N integers and an integer K, returns the array A rotated K times, one function must return the array rotated to the right and the other the array rotated to the left


  1. Write a function in Python, that given two strings as inputs returns whether one is an anagram of the other, for example it returns True for the inputs night and thing

Linux & Operating Systems Questions

  1. What is the kernel of an OS?

  2. What's the difference between user mode and kernel mode?

  • Usually user applications run in user mode and when it requests a service from the operating system the system must transition from user to kernel mode to fulfill the request
  • User mode: executing code has no ability to directly access hardware, reference memory or other resources
  • Kernel mode: executing code has access to the underlying hardware and resources and it can execute restricted CPU instructions

  1. What do applications running in user mode use to request a service from the OS

  2. What is a Linux Distribution? What differentiate Linux distributions?

  • Linux Distro is combination of the Linux kernel with other system components (or programs/packages) to make a Linux based OS. So the programs, packages that are included, the windows manager and the package manager are a few singularities for each distro
  • A custom build of the GNU/Linux operating system combined with other programs/packages

  1. What do you need to compile the Linux kernel?
  • In general you need a compiler (E.g. gcc) and the Linux kernel sources (.c, .h… files) files. You can do native build or cross compile

  1. What is the difference between a Thread and a Process?
  • Both processes and threads are independent sequences of execution
  • Threads are of the same process and run in a shared memory space (E.g. a process can have multiple threads running independently to solve a problem)
  • Processes run in separate memory space (A Process is usually associated with a running program instance and inside that process there could be multiple Threads)


Embedded Systems & RTOS Questions

  1. What is a Timer?
  • A peripheral used to measure time usually implemented with a counter

  1. What is an Interrupt?
  • An event that interrupts the software and transfer it's execution to a handler or specific code section.
  • Book Definition: An interrupt is the automatic transfer of software execution in response to a hardware event that is asynchronous with the current software execution.

  1. How does an ADC work in general?
  • At a SW level it needs to be configured to define it's sample rate, it's trigger mechanism (usually can be by SW or by other peripheral), if its going to cause interrupts, once configured we need to trigger it's operation to then read the register that holds the ADC conversion then usually clear the flags and repeat the process
  • At a HW level it can be implemented using analog comparators, a DAC and a generator of digital values

  1. What is the difference between ROM and Flash memory?
  • Both are non-volatile so they preserve it's data after power is removed
  • A ROM It's a pure Read-Only Memory so it's content cannot be modified, its content is usually stored as part of the manufacturing process (E.g. fuses)
  • A Flash It's a type of EEPROM (Electrically Erasable Programmable Read-Only Memory) that can be erased and programmed electrically (usually in blocks of specific size)

  1. What is the difference between a HW breakpoint and a SW breakpoint?
  • A Hardware Breakpoint is implemented using special logic that is integrated into the device. For example with a set of programmable comparators that are connected to the program address bus.
  • A Software Breakpoint is implemented in software usually with a special instruction (opcode) that gets inserted in the code

  1. What is a Race Condition?
  • A race condition occurs when two or more threads can access shared data/resource and they try to change it. Therefore, the result of the change is dependent on the order the threads execute, which could cause unexpected results if we need the shared data/resource to be accessed in a specific order. It is a race condition because both threads are "racing" to access/change the data.


Validation, Verificaion, Testing

  1. What is the difference between Validation and Verification?
  • Verification: is intended to check that something (a product, service, software, or system) meets a set requirements (design specifications)
  • Validation: is intended to ensure that something (a product, service,software, or system) meets the operational needs of the user (informally meets user expectations and use cases)
  • These definitions can vary depending on the context and in practice are usually used interchangeably

  1. What is a Test Case and an Use Case?
  • Test Case: It is what documents all the conditions, procedures and inputs that are needed to execute a single test and the expected outputs of the test
  • Use Case: It is what describes the user action and system response for a particular functionality, one Use Case can have many Test Cases.

  1. What is a Test Plan?

  2. What is a Bug?

  3. From the testing perspective what is done when a Bug is found? What is the Bug life cycle from a testing perspective?

  4. What is the difference between 'White Box' and 'Black Box' Testing?

  • White Box: is a testing methodology that tests internal structures or workings of system, it test internal paths and functionality of the system
  • Black Box: is a testing methodology which is used to test without knowing the internal structure of code or system only focusing on inputs and outputs or the external interfaces of a system

Other Questions

  1. Explain what is make and a Makefile?
  • make: is a dependency resolver program that controls the generation of files and usually executables (and libraries)
  • Makefile: file used by the make utility that has the knowledge of how to build/generate an executable, program or other file(s)

  1. What is the difference between a Shared and a Static Library?
  • Shared Library: they are usually .so or .dll files, all the code relating to the library is in this file, which it is referenced by programs using it at run-time. A program using a shared library only makes references to the code, it doesn't hold a copy of the code. Reduce program size and independency between code but increases loading cost and places a dependency on the system running the program
  • Static Library: they are usually .a or .lib files, all the code relating to the library is in this file and it is directly linked into the program at compile time. A program using a static library takes copies of the code that it uses from the static library and makes it part of the program. Increase size of program but improves speed and removes run time dependencies

  1. In a software context what is the main difference between a Framework and a Library?
  • Both can be defined as collection of software (classes, methods, functions, objects, etc.) but the main difference is who or what is in control, something also known as Inversion of Control (IoC)
  • A Framework: helps you create a specific type of application (e.g. Web application, a GUI app, a mobile app, etc.) but it requires the user to define/create certain functionality, this means your code is called by the framework who is the one that is actually in control of the flow
  • A Library: helps you perform specific operations (e.g. mathematical complex number operations, string manipulation, image compression, etc.) and the library is called by your code or application, this means your code has the main control of the flow

Want to show support?

If you find the information in this page useful and want to show your support, you can make a donation

Use PayPal

This will help me create more stuff and fix the existent content...