Embedded interview questions (2)

Content from the Internet, collated in 2020

 

1. The output of the following code is:

void change(int* a, int& b, int c)
{
    c = *a;
    b = 30;
    *a = 20;
}
int main ()
{
    int a = 10, b = 20, c = 30;
    change(&a, b, c);
    printf(“ % d, % d, % d, ”, a, b, c);
    return 0;
}

Answer: 20, 30, 30

2. The default ports of FTP service and SMTP service are ()

Answer: 20, 21; 25

3. When the linear table (a1, a2, ..., an) is stored in a linked manner, the time complexity of accessing the i-th position element is ()

Answer: O (n)

4. What is the size calculated with sizeof (struct A) under 64-bit compiler?

struct A {
    long a1;
    short a2;
    int a3;
    int* a4;
};

Answer: 4 byte alignment is 16

8 byte alignment is 24

5. Do a binary search on an ordered array with 20 elements. The starting index of the array is 1, and the index of the comparison sequence of A [2] is ()

Answer: 10, 5, 3, 2

6. On a B-tree of order 10, the number of keywords in each root node is allowed to be () at most, and at least ().

Answer: 9; 4

7. The operating system uses buffering technology to increase the utilization of resources by reducing the number of CPU cycles.

Answer: Interrupt

8. What are the trigger modes of the oscilloscope?

Answer: There are three trigger modes: automatic, normal and single trigger.

 

9. The byte size of common basic types

32-bit operating system

char: 1 byte (fixed)

* (Namely pointer variable): 4 bytes (the address space of 32-bit machine is 4 bytes)

short int: 2 bytes (fixed)

int: 4 bytes (fixed)

unsigned int: 4 bytes (fixed)

float: 4 bytes (fixed)

double: 8 bytes (fixed)

long: 4 bytes

unsigned long: 4 bytes (variation *, in fact, the address length value of the addressing control)

long long: 8 bytes (fixed)

 

10. Pointer to string constant, constant pointer to string (const)

const char * p = "hello"; // points to "string constant"

p [0] = 'X'; // Error! You want to modify the first character of the string. But the constant does not allow modification

p = p2; // Correct! Let p point to another pointer.

char * const p = "hello"; // "const pointer to string"

p [0] = 'X'; // Correct! Allow modification of the string, because the string is not a constant

p = p2; // Error! The pointer is a constant, it is not allowed to modify the pointer of p

char const * is the same as const char *. The position of const is the same on the left or right of char.

The const of a constant pointer should be written to the right of the * asterisk.

The writing of a constant pointer to a constant string is const char * const p = "xx"; 2 const

This analysis is better than the previous article.

 

11. The problem of typedef & #define

There are two ways to define the pStr data type. What is the difference between the two? Which one is better?

typedef char* pStr;

#define pStr char*;

Analysis: Generally speaking, typedef is better than #define, especially when there are pointers. Please see examples:

typedef char* pStr1;

#define pStr2 char *

pStr1 s1, s2;

pStr2 s3, s4;

In the above variable definitions, s1, s2, and s3 are all defined as char *, while s4 is defined as char, not the pointer variable we expected,

The fundamental reason is that #define is simply a string replacement and typedef is to give a new name to a type. In the above example, the define statement must be written as pStr2 s3, * s4; This can be executed normally.

 

12. The problem of const

(1) const constants can be defined, with immutability.

E.g:

const int Max=100; int Array[Max];

(2) It is convenient for type checking, so that the compiler has more understanding of the processing content, eliminating some hidden dangers.

E.g:

 void f ( const  int i) {.........} // The compiler will know that i is a constant and does not allow modification;

(3) The appearance of ambiguous numbers can be avoided, and the adjustment and modification of parameters can also be easily carried out.

As in (1), if you want to modify the contents of Max, you only need to: const int Max = you want;

(4) It can protect the modified things, prevent accidental modification, and enhance the robustness of the program. Still the above example, if i is modified in the function body, the compiler will report an error;

E.g:

 void f(const int i) { i=10;//error! }

(5) It can save space and avoid unnecessary memory allocation. E.g:

#define PI 3.14159 // Constant macro 
const  double Pi = 3.14159 ; // At this time, Pi is not put in RAM
double i = Pi; // allocate memory for Pi at this time, no longer allocated in the future! 
double I = PI; // Macro replacement during compilation, memory allocation
double j = Pi; // No memory allocation 
double J = PI; // Replace the macro and allocate memory again!

const defines constants from the assembly point of view, but only gives the corresponding memory address, instead of giving immediate data like #define,

Therefore, the constants defined by const have only one copy during the running of the program, while the constants defined by #define have several copies in memory.

(6) Improve efficiency.

The compiler usually does not allocate storage space for ordinary const constants, but saves them in the symbol table, which makes it a constant during compilation, without storage and read memory operations, making it very efficient.

 

13. The difference between sizeof and strlen:

char str[20]="0123456789";

int a = strlen (str); // a = 10; strlen Calculate the length of the string, with \ 0 'as the end tag of the string.

int b = sizeof (str); // b = 20; sizeof calculates the size of the memory space occupied by the allocated array str [20], which is not affected by the content stored in it.

 

The above is the result of processing the static array. If it is the pointer, the result is different.

char * ss = " 0123456789 " ; // sizeof (ss) result 4

 

ss is a character pointer pointing to a string constant, sizeof is a pointer to occupy the space, it should be a long integer, so it is 4

sizeof (* ss) // Result 1; * ss is the first character is actually the memory space occupied by the first bit '0' of the string, which is of the char type and occupies 1 bit

 

strlen (ss) = 10  // If you want to get the length of this string, you must use strlen

 

The Sizeof structure is the total space of the data types defined in the structure (note the byte alignment).

Sizeof (union) is the size of the largest data type of the data type defined in union.

 

14, auto, register, static analysis

Auto is the default attribute of local variables in the C language. The compiler defaults that all local variables are auto, and the defined variables are allocated memory on the stack .

The static keyword indicates the "static" attribute of the variable, and also has the meaning of "scope qualifier". The modified local variables are stored in the static area of ​​the program . Another meaning of static is the file scope identifier.

Static modified global variable scope is only in the declared file, static modified function scope is only in the declared file

The register keyword indicates that the variable is stored in the register. The register only requests the register variable, but the request is not necessarily successful. The register variable must be a value that the CPU register can accept,

You cannot use the & operator to obtain the address of a register variable. The advantage of this is that it is fast to process.

 

15, const, volatile modify variables at the same time

( 1 ) "The compiler generally does not allocate memory for const variables, but saves it in the symbol table, which makes it a value during compilation, without storing and reading memory."
( 2 ) The role of volatile is to "tell the compiler that i may change at any time, and the value of i must be fetched from memory each time it is used."

 

16, const, volatile meaning

( 1 ) The meaning of const is "please use it as a constant", not "rest assured, it must be a constant".
( 2 ) The meaning of volatile is "please don't do self-righteous optimization, this value may change", not "you can modify this value".

 

17. The role and stage of const, volatile

(1) const is only useful at compile time, useless at runtime

const guarantees that there is no place to modify its modified variables in C "source code" at compile time (if there is an error, compilation fails), and whether the value of the variable is changed at runtime is not subject to const limit.

(2) Volatile is useful at compile time and run time

Tell the compiler at compile time: Please do not make self-righteous optimizations, the value of this variable may change;

During runtime: Every time the value of the variable is used, the value of the variable is taken from the memory.

Supplement: Compilation period-the process by which the C compiler converts source code into assembly and then into machine code; runtime-the process of machine code executing in the CPU.

 

18. const, volatile modify a variable at the same time

(1) Legality

The meaning of "volatile" is not "non-const", volatile and const do not constitute antonyms, so you can put together to modify a variable.

(2) Modify the meaning of a variable at the same time

Indicates that a variable cannot be modified and cannot be optimized during program compilation; the value of the variable can be modified during program execution, but the value of the variable must be read from memory each time it is used to prevent accidental errors.

 

19. Stack, heap, static storage area

Stack: Use of main function calls

The stack is used from the high address to the low address, and the heap is in the opposite direction.

In a function call, the stack will be pushed in order: parameters, return address, EBP. If the function has local variables, next, open up the corresponding space on the stack to construct the variables.

In a C language program, the order of stacking parameters is reversed. For example, func (a, b, c). When the parameters are pushed into the stack, it is: first press c, then press b, and finally a. When fetching parameters, due to the first-in, first-out of the stack, first take a at the top of the stack, then take b, and finally take c.

Heap: dynamic allocation of main memory

Idle list method, bitmap method, object pool method, etc.

Int* p=(int*)malloc(sizeof(int));

 

Static storage area: save global variables and static variables

The static storage area of ​​the program allocates space as the program runs until the end of the program. The size of the static storage area has been determined during the compilation of the program. The static storage area of ​​the program is mainly used to save global variables and static variables The stack and heap are different, and the information in the static storage area will eventually be saved in the executable program.

Knowledge point: The stack segment only officially exists after the program runs, which is the basis of the program.

1. The function is placed in the code section: .Test section. The .text section stores the executable code in the program
 2. Global variables and static variables with initial values ​​are in the data section: .data section. Save .data section are those that have been initialized global variables and static variables
 3 . Without the initial worth of global variables and static variables in .bss. The .bss section stores uninitialized global variables and static variables
The .rodata (read only) section stores constant values ​​in the program, such as string constants

 

20. Both are global variables and static variables. Why are initialized and uninitialized variables stored in different segments?

Answer: In order to simplify the startup code, the compiler linker will put the initialized variables in the same segment: .data, the image of this segment (including the initial value of each variable) is saved in the "read-only data segment", so The boot code can simply copy this image to the .data section and all initialized variables are initialized. Uninitialized variables are also placed in the same section: .bss. The startup code simply calls memset to clear all uninitialized variables.

void *memset(void *s, int ch, size_t n);

Function explanation: replace n bytes (typedef unsigned int size_t) after the current position in s with ch and return s.

memset: the role is to fill a given value in a block of memory, it is the fastest way to clear a large structure or array

21. Wild pointer

cause:

1. The local pointer variable is not initialized

2. Use the pointer that has been released

3. The variable pointed to by the pointer is destroyed before the pointer

Avoidance measures:

A. After applying for memory with malloc, you should immediately check whether the pointer value is NULL to prevent the use of a pointer that is NULL:

B. Keep in mind the length of the array to prevent array out of bounds operation, consider using a flexible array

C. The dynamic application operation must match the release operation to prevent memory leaks and multiple releases

D. Free pointer must be assigned a value of NULL immediately

22, void type pointer

The pointer has two properties: the address and length of the variable / object, but the pointer only stores the address, and the length depends on the type of pointer;

The compiler addresses backwards from the address pointed to by the pointer according to the type of pointer, and the addressing range is different for different pointer types, such as:

int * finds 4 bytes as a variable storage unit backward from the specified address

double * looks for 8 bytes as a variable storage unit backward from the specified address

void is "untyped", and void * is "untyped pointer", which can point to any data type.

A void pointer can point to any type of data, that is, a pointer of any data type can be used to assign a value to a void pointer.

E.g

int *pint;

void * pvoid; // It has no type, or this type cannot determine the length of the pointed object 

pvoid = pint; // Only get the variable / object address and not the size, but cannot pint = pvoid;

 

If you want to assign pvoid to other types of pointers, you need to force type conversion such as:

pint = ( int *) pvoid; // The conversion type is to get the size of the pointed variable / object

 

The void pointer cannot be re-referenced (that is, take the meaning of the content)

* pvoid // error 

If you want to re-reference a pointer, or use the " -> " operator to re-reference a part, you must have an interpretation rule for the memory pointed to by the pointer.

For example, int * p;

Then, when you copy p later, the compiler will treat the four bytes starting from the address pointed to by p as an integer complement.

Because the void pointer only knows the starting address of the variable / object, and does not know the size of the variable / object (a few bytes), it cannot be properly referenced.

In the actual program design, in order to meet the ANSI standard and improve the portability of the program, we can write code that achieves the same function like this:

void *pvoid;

( char *) pvoid ++; // ANSI: correct; GNU: correct 

( char *) pvoid + = 1 ; // ANSI: incorrect; GNU: correct

 

Guess you like

Origin www.cnblogs.com/kunx/p/12753161.html