Key Excerpt from C language (interview question analysis and doubt analysis) (complete)

Source: Internet
Author: User

37. Interview Analysis

1. pointer operation

#include <stdio.h>void main(){    int TestArray[5][5] = { {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}                          };    int* p1 = (int*)(&TestArray + 1);//    int* p2 = (int*)(*(TestArray + 1) + 6);    printf("Result: %d; %d; %d; %d; %d\n", *(*TestArray), *(*(TestArray + 1)),                                            *(*(TestArray + 3) + 3), p1[-8],                                            p2[4]);}

Output result:

Result: 11; 16; 29; 28; 26

Test site: array name pointer operation: P + N; <----------> (unsigned INT) P + N * sizeof (* P); P1 points to the address behind the two-dimensional array

Differences between A and: A is the address of the first element of the array. A is the address of the entire array. The difference between A and A is that the pointer operation is a + 1 ---> (unsigned INT) A + sizeof (* A) & A + 1 ----> (unsigned INT) (& A) + sizeof (* & A) = (unsigend INT) (&) + sizeof ()

Two-dimensional arrays are stored in the memory as one-dimensional arrays. * (testarray + 1) represents the address of the second array. * (testarray
+ 1) + 6 points to the next move of six units

2. debugging experience

#include<stdio.h>void main(){    char* p = "hello world!";    int a = (int)p;    short s = 'c';    printf("%c\n", (long)(*((int*)p)));    printf("%s\n", a);    printf("%s\n", &s);}

Output:

hhello world!c

1. P is the first address of the string, P is a 32-bit integer, is an address value, (int *) P is converted into a pointer to an integer, * (int *) p) retrieve the four bytes from the beginning of the address and get the hell (printf lost type information). The value is converted to the long type and parsed in C, that is, H.

2. Print the string starting with the address represented by a for the string type
3. it is a string that is printed in the string type and starts with the address represented by & S. Short is two bytes, C occupies one byte, And the other byte is 0. Therefore, only C is printed (it is related to the large and small ends)

Summary: Variable Parameter functions cannot be used to detect the parameter type. It must be parsed by input parameters.

3. Security Programming

#include<stdio.h> int main(int argc, char *argv[]) {     int flag = 0;     char passwd[10];     memset(passwd,0,sizeof(passwd));     strcpy(passwd, argv[1]);     if(0 == strcmp("LinuxGeek", passwd))     {         flag = 1;     }     if( flag )     {         printf("\n Password cracked \n");     }     else     {         printf("\n Incorrect passwd \n");     }     return 0; }

Resolution: If you enter a password of more than 10 bytes, the password will be correct, because the function stack increases from the high address to the low address, and strcpy will replace the flag value when copying more than 10 Characters


Security summary:

1. Check input parameters

2. Check whether the return value in the function call is correct.

3. Assert assertions

4. Use string library functions with N, such as strncpy instead of strcpy

5. Do not use expressions with side effects (for example, expressions with different operation sequences in different compilers.


Q &:

1.

# Include <stdio. h> int main () {printf ("% F \ n", 5); printf ("% d \ n", 5.01);} output: neither of them is 5


First, printf is a variable parameter function. I mentioned in the course that the variable parameter function does not have parameter type information. Therefore, "% d" % C "in printf is used to identify parameter type

Second, the internal representation of integers and floating-point numbers in the computer is different. In C, 5 defaults to 5.01 of int, and double by default. Their internal representation is completely different.
Printf ("% F \ n", 5); here an int representation is interpreted as a floating point.
Printf ("% d \ n", 5.01); here an integer is used to explain a float representation.


2.

#include <stdio.h>int main(){int k;while(1){scanf("%d",&k);printf("%d\n",k);if(k==2)break;}return 0;}

Resolution:

The value of printf K is always the value of the previous input, but the value in the keyboard buffer is always invalid characters. Therefore, scanf jumps out of the loop every time. add the last fflush (stdin ); this program won't die.


Modify:

#include <stdio.h>int main(){int k=9;while(1){scanf("%d",&k);printf("%d\n",k);if(k==2)break;fflush(stdin);}return 0;

Summary:

When the scanf () function receives input data, it ends a data input in the following circumstances: (instead of ending the scanf function, the scanf function only has data in each data field and ends after pressing enter ).
① In case of space, "enter", and "Skip" keys.
② End with width.
③ Illegal Input


3. About const and volatile

Const and volatile can modify a variable at the same time. Const only indicates that the variable is read-only and cannot appear on the left of the value assignment number. This prevents the program from "accidental" modification and the compiler will definitely optimize it,
Does not remove the memory value each time. At this time, if an external event, such as a service program interruption, changes the memory value of this variable, the compiler optimization will not respond, which will lead to errors.
When volatile is added, the compiler is told not to perform any optimization, and the memory value is removed each time. This variable cannot be used as the left value.

void f(){    const int count = 5;    int i = 0;    for(i=0; i<count; i++)    {        sleep(500);    }}

Can this program be confirmed that this loop must be performed five times?

The modern compiler must be five times in this case. during compilation, the compiler thought it was a const, and the value could not be changed in this function, instead of 5.
All local variables are in the memory. They all have addresses. For embedded programs like single-chip microcomputer that do not have an operating system, the addresses of local variables can even be calculated directly.


4. sizeof

What is the output of the following program?

int f(){    static int i = 0;    i++;   return i;}int main(){   int j = sizeof(f());   printf("%d\n", f());    return 0;}

I emphasize that sizeof is not a function but a keyword used by the compiler. Therefore, the value of sizeof is determined during the compilation period, so the first F () is not called.
F () is called only once, and the length of the F return value can be determined at compilation without waiting for the runtime.

5. System Alignment

The 32-bit system defaults to 4-byte alignment, and 64 is the default 8-byte alignment.


#include<stdio.h>struct TestC{        char a;        char mac[6];}cc;struct TestD{        char a;        char mac[6];        char pad[1];}dd;struct x{ char a; int b; char c;}ee;int main(){printf("%d\n",sizeof(cc));//7printf("%d\n",sizeof(dd));//8printf("%d\n",sizeof(ee));//12}

Align according to the size of the struct member type and the minimum value of the alignment parameter (space alignment and address alignment)

5.

Question 1:
What are the essential differences between the following functions? Which one do you choose? Why?


void fun1(int a[], int x, int b[], int y, int n){    int i = 0;    for(i=0; i<n; i++)    {        a[i * x] = b[i * y];    }}void fun2(int a[], int x, int b[], int y, int n){    int i = 0;    for(i=0; i<n; i++)    {        *a = *b;        a += x;        b += y;    }}

In fact, from the perspective of the question, we certainly chose 2 because the second type is more efficient. The efficiency of computer addition is much higher than that of the program.

But we should not ignore the readability. In fact, the first method is highly readable from the perspective of C.

If we want to consider program portability and efficiency, the second reason is that the second method directly replaces multiplication with addition at the source code level, which improves the efficiency and is efficient to any C compiler.


The first method is the method with good readability but not efficient. but now many c compilers have optimization options. When we enable the optimization options during compilation, the idea rate between the two is actually the same, but we it cannot be ensured that all c compilers can optimize compilation.


Question 2:
What are the differences between the following two programs? Why?


Procedure 1: for (I = 0; I <m; I ++) {for (j = 0; j <n; j ++) {for (k = 0; k <p; k ++) {C [I] [J] + = A [I] [k] * B [k] [J] ;}} Program 2: for (I = 0; I <m; I ++) {for (k = 0; k <p; k ++) {for (j = 0; j <N; j ++) {C [I] [J] + = A [I] [k] * B [k] [J] ;}}

From the perspective of the program, the two achieve the same functional difference, but the second and third layers are switched cyclically.
However, their difference is huge. This requires the CPU cache. Each time the CPU accesses the memory, it first reads data from the memory into the cache and then retrieves data from the cache.

However, the cache size is limited. Therefore, only some of the data is transferred to the cache. Each time we put a piece of memory into the cache, we only use the data near one of the arrays.

Let's look at this program c [I] [J] = A [I] [k] * B [k] [J];

We all know that the two-dimensional arrays in C are arranged in one dimension in the memory. If we put the K loop on the third layer, the cache is basically useless and we need to retrieve data from the memory every time.

After the switch, the data obtained from the cache can be reused multiple times.

Therefore, the second method is highly efficient.



Question 3:
The strcmp function is used to determine whether a string is equal. The same memcpy can also be used to determine whether a string is equal. What is the difference between the two? Why?

From the perspective of C language and problem 2 cache

The comparison Terminator '\ 0' of the first strcmp is closely related. That is to say, it is not safe because memcmp needs to provide length during the comparison, which is more secure. This is from the perspective of C security programming. to analyze

Second Efficiency
Strcmp is a comparison of one character and one character, that is to say, the CPU needs to "find a way" to compare only one byte while memcmp compares four or eight bytes at a time based on the features of the hardware platform.

From the cache, we can see that strcmp reads a piece of data into the cache and compares it with only one byte. memcmp enters the cache each time and performs block comparison based on CPU preferences.


6. Share a tip

int a;int* p = &a;void* pv = p;printf("%d\n", *pv);

PV is the address pointing to a. If we don't want to know the specific data type pointing to the pointer, we can use the void * pointer to point to the specific address in my Data Structure course. this technique is used because people who do not want to use the data structure I have created know how to represent the data structure, such as the head of the linked list. So I use the void * pointer to return








Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.