[school recruitment manual] after learning C language, have you mastered all these interview questions?

Posted by moonoo1974 on Sun, 06 Mar 2022 01:49:57 +0100

Hello, everyone. I'm safe and sound.

Each Preface

Blog home page: Safe and sound

Author introduction: 2021 blog star Top2

Our slogan: 🌹 Little bit, big dream 🌹

Author's request: due to the limited level of bloggers, it is inevitable that there will be mistakes and inaccuracies. I am also very eager to know these mistakes and beg iron juice to criticize and correct them.

Popular column: Analysis of basic algorithm of Blue Bridge Cup

First, review a knowledge point:

Traditional element name

There are two exceptions:

  1. Sizeof (array name): put a single array name into sizeof. At this time, the array name no longer represents the address of the first element, but the whole array. It calculates the size of the whole array in bytes (note this single!);
  2. &Array name: the address of the whole array is taken out.

OK, after introducing this knowledge point, please look at the following series of written examination questions:

1, One dimensional array

//One dimensional array
#include<stdio.h>

int main()
{
	int a[] = { 1,2,3,4 };

	printf("%d\n", sizeof(a));//16
	//A single array name a is put into sizeof. At this time, the array name represents the whole array and calculates the size of the whole array (note this single!)

	printf("%d\n", sizeof(a + 0));//4 / 8 - 4 bytes on 32-bit platforms and 8 bytes on 64 bit platforms
	//At this time, more than one array name a is placed in sizeof, so a represents the address of the first element, the type is int *, a+0 skips 0 integers, and represents the address of the first element
	//The address is the pointer. The pointer occupies 4 bytes on the 32-bit platform and 8 bytes on the 64 bit platform

	printf("%d\n", sizeof(*a));//4
	//At this time, a represents the address of the first element. Dereference it and get the first element. Therefore, the size of the first element is calculated here

	printf("%d\n", sizeof(a + 1));//4/8
	//At this time, a represents the address of the first element, the type is int *, and a+1 skips an integer, so a+1 represents the address of the second element, that is, the address of 2

	printf("%d\n", sizeof(a[1]));//4
	//The size of the second element is calculated

	printf("%d\n", sizeof(&a));//4/8
	//&A takes out the address of the whole array, the type is int(*)[4], which belongs to the array pointer, and the array pointer is still a pointer

	printf("%d\n", sizeof(*&a));//16
	//Understanding 1: it can be considered that the * and & Operations offset. At this time, only sizeof (a) is left. A represents the whole array and calculates the size of the whole array;
	//Understand 2: & A, take out the address of the whole array, the type is int(*)[4] array pointer type, and then dereference it. At this time, the whole array is accessed, and the size is 16 bytes

	printf("%d\n", sizeof(&a + 1));//4/8
	//&A takes out the address of the whole array, and the type is int(*)[4] array pointer, & A + 1 skips the address of the whole array, which is 4 / 8 bytes

	printf("%d\n", sizeof(&a[0]));//4/8
	//&A [0], the address of the first element is taken out

	printf("%d\n", sizeof(&a[0] + 1));//4/8
	//&A [0] + 1, skip 1 integer, so & A [0] + 1 accesses the address of the second element

	return 0;
}

2, Character array

1. Question type I

Note the concept:

sizeof:

  1. sizeof only focuses on the size of occupied space;
  2. sizeof does not focus on types;
  3. sizeof is the operator

strlen():

  1. strlen() focuses on the number of characters before '\ 0' in the string;
  2. strlen() is only for strings;
  3. strlen() is a library function

OK, look at the following code:

Code 1:

#include<stdio.h>

int main()
{
	char arr[] = { 'a','b','c','d','e','f' };

	printf("%d\n", sizeof(arr));//6
	//The size of the entire array is calculated

	printf("%d\n", sizeof(arr + 0));//4/8
	//The address of the first element is calculated

	printf("%d\n", sizeof(*arr));//1
	//The size of the first element is calculated

	printf("%d\n", sizeof(arr[1]));//1
	//The size of the second character is calculated

	printf("%d\n", sizeof(&arr));//4/8
	//&Arr, the address of the whole array is taken out, and the address is the pointer

	printf("%d\n", sizeof(&arr + 1));//4/8
	//&Arr + 1, skipping the entire array, but still the address

	printf("%d\n", sizeof(&arr[0] + 1));//4/8
	//&Arr [0] indicates the address of the first character and the type is char *, so & arr [0] + 1 skips one character and points to the address of the second character

	return 0;
}

Code 2:

#include<stdio.h>

int main()
{
	char arr[] = { 'a','b','c','d','e','f' };

	printf("%d\n", strlen(arr));//Random value
	//strlen() encounters the end of '\ 0', which counts the number of characters before '\ 0', but there is no '\ 0' in arr, so it doesn't know where to end, so here is a random value

	printf("%d\n", strlen(arr + 0));//Random value
	//ditto

	printf("%d\n", strlen(*arr));//Memory access violation
	//The parameter in strlen() is the pointer type (it can be considered that the address is stored in it), * arr represents the first element, that is, 'a', and the ACSII value of 'a' is 97,
	//Therefore, strlen(*arr) accesses' 97 'as a memory address, which will lead to memory access conflict

	printf("%d\n", strlen(arr[1]));//Memory access violation
	//As above, arr[1] indicates' b',ACSII value is 98, and strlen(arr[1]) indicates that' 98 'is accessed as a memory address

	printf("%d\n", strlen(&arr));//Random value
	//&Arr, the address of the whole array is taken out. Since there is no '\ 0' in the array, I don't know where it will end

	printf("%d\n", strlen(&arr + 1));//Random value

	printf("%d\n", strlen(&arr[0] + 1));//Random value

	return 0;
} 

Here's another emphasis on this line of code:

printf("%d\n", strlen(*arr));

strlen() needs an address. Start from this address and look for characters backward until '\ 0', which counts the number of characters before '\ 0', but * arr represents the first element, that is, 'a'. At this time, the ACSII value 97 of 'a' is passed to strlen(). strlen() will take 97 as the starting address to count the string, which will also form a memory access conflict.

2. Question type 2

Code 1:

#include<stdio.h>

int main()
{
	char arr[] = "abcdef";

	printf("%d\n", sizeof(arr));//7
	//Note that sizeof(arr) calculates the memory space occupied by the arr array, including '\ 0'

	printf("%d\n", sizeof(arr + 0));//4/8
	//It's relatively simple. I'll just go over it
	printf("%d\n", sizeof(*arr));//1

	printf("%d\n", sizeof(arr[1]));//1

	printf("%d\n", sizeof(&arr));//4/8

	printf("%d\n", sizeof(&arr + 1));//4/8

	printf("%d\n", sizeof(&arr[0] + 1));//4/8

	return 0;
}

Code 2:

With the above experience, you will not be difficult below!

#include<stdio.h>

int main()
{
	char arr[] = "abcdef";

	printf("%d\n", strlen(arr));//6

	printf("%d\n", strlen(arr + 0));//6

	printf("%d\n", strlen(*arr));//Memory access violation

	printf("%d\n", strlen(arr[1]));//Memory access violation

	printf("%d\n", strlen(&arr));//6 (pay special attention here)

	printf("%d\n", strlen(&arr + 1));//Random value

	printf("%d\n", strlen(&arr[0] + 1));//5

	return 0;
}

3. Question type III

Code 1:

#include<stdio.h>

int main()
{
	char* p = "abcdef";

	printf("%d\n", sizeof(p));//4/8

	printf("%d\n", sizeof(p + 1));//4/8

	printf("%d\n", sizeof(*p));//1

	printf("%d\n", sizeof(p[0]));//1

	printf("%d\n", sizeof(&p));//4/8

	printf("%d\n", sizeof(&p + 1));//4/8

	printf("%d\n", sizeof(&p[0] + 1));//4/8

	return 0;
}

Code 2:

#include<stdio.h>

int main()
{
	char* p = "abcdef";

	printf("%d\n", strlen(p));//6

	printf("%d\n", strlen(p + 1));//5

	printf("%d\n", strlen(*p));//Memory access violation

	printf("%d\n", strlen(p[0]));//Memory access violation

	printf("%d\n", strlen(&p));//Random value (note that this is a particularly error prone place, which is particularly easy to be written as 6)
	//What I want to say here is that p refers to constant string, which is different from character array. p has its own space

	printf("%d\n", strlen(&p + 1));//Random value

	printf("%d\n", strlen(&p[0] + 1));//5

	return 0;
}

Supplementary constant string

Among pointer types, we know that one pointer type is char *, which can be used in two ways:

General use:

 #include<stdio.h>
 
 int main()
 {
      char ch = 'w';
      char* pc = &ch;
      *pc = 'a';
      printf("%c\n", ch);

      return 0;
 }

This method of use is relatively simple. I won't elaborate more. Let's take a look at the following method of use:

 #include<stdio.h>
 
 int main()
 {
      char* p = "abcdef";
      printf("%s\n", p);
      return 0;
 }
  1. Note that the above abcdef is a constant string and is stored in the read-only data area of memory (read-only and not writable)

  2. It's very easy for us to think that we are putting the string abcdef into the character pointer p. in fact, it is essentially putting the address of the first character of the string abcdef into p

So the following code is problematic:

#include<stdio.h>
 
 int main()
 {
      char* p = "abcdef";
      *p = 'w';//The purpose is to change 'a' to 'w' (bug)

      return 0;
 }

The code in line 6 above is wrong. Because the constant string cannot be modified, in order to avoid the above error, the code in line 5 can be modified as follows:

const char* p = "abcdef";

In this way, the above mistakes will be avoided.

Interview questions:

#include <stdio.h>

int main()
{
    char str1[] = "hello bit.";
    char str2[] = "hello bit.";
    char* str3 = "hello bit.";
    char* str4 = "hello bit.";
    if (str1 == str2)
        printf("str1 and str2 are same\n");
    else
        printf("str1 and str2 are not same\n");

    if (str3 == str4)
        printf("str3 and str4 are same\n");
    else
        printf("str3 and str4 are not same\n");

    return 0;
}


Problem solving ideas:

  1. str1 and STR2 are two character arrays. The operation mode of the array is to copy the constant string on the right into the space of the array, so they are two spaces with the same content. As the array name, str1 and STR2 are the address of the first element of the array, so str1= str2
  2. str3 and str4 are two character pointers pointing to the same constant string, and the constant string is stored in a separate memory area (read-only data area). When several pointers point to the same constant string, they will actually point to the same memory

3, Two dimensional array

#include<stdio.h>

int main()
{
	int arr[3][4] = { 0 };

	printf("%d\n", sizeof(arr));//12*4=48
	//Sizeof (array name), which calculates the size of the entire array in bytes

	printf("%d\n", sizeof(arr[0][0]));//4
	
	printf("%d\n", sizeof(arr[0]));//4*4=16
	//arr[0] is equivalent to the array name in the first row. Since it is placed separately in sizeof, it calculates the size of the array in the first row in bytes

	printf("%d\n", sizeof(arr[0] + 1));//4/8
	//arr[0] is equivalent to the array name of the first row. Since it is not placed separately inside sizeof, arr[0] at this time represents the address of the first element of the first row

	printf("%d\n", sizeof(*(arr[0] + 1)));//4
	//As mentioned earlier, arr[0] represents the address of the element at the beginning of the first line, so * (arr[0] + 1) represents the element itself of arr[0][1]

	printf("%d\n", sizeof(arr + 1));//4/8
	//The ARR array name represents the address of the first element, that is, the address of the first row array, so arr+1 represents the address of the second row array

	printf("%d\n", sizeof(*(arr + 1)));//4*4=16
	//As mentioned earlier, arr+1 represents the address of the second row array. When dereferencing it, it accesses the second row array, which is placed separately in sizeof, and calculates the size of the second row array

	printf("%d\n", sizeof(&arr[0] + 1));//4/8
	//&Arr [0] indicates the address of the first row array, then & arr + 1 indicates the address of the second row array, and the address is the pointer

	printf("%d\n", sizeof(*(&arr[0] + 1)));//4*4=16
	//As mentioned earlier, & arr [0] + 1 represents the address of the second row array, so its dereference represents the second row array, which is placed separately in sizeof, and the size of the second row array is calculated

	printf("%d\n", sizeof(*arr));//4*4=16
	//arr represents the address of the first element, that is, the address of the first row array. Dereferencing it represents the first row array, which is placed separately in sizeof, and the size of the first row array is calculated

	printf("%d\n", sizeof(arr[3]));//4*4=16
	//Here, we may think that arr[3] is out of bounds, but it does not affect this question. sizeof will deduce that the type of arr[3] is int[4]

	return 0;

}

4, Analog implementation of string library functions

1.strlen()

Function prototype:

Function function:

Find the length of the string

Note: return value type It's size_t. This size_ What exactly is t?

Actually size_t is for sizeof The return value of the operator is designed, which can be considered as size_t is the well-known unsigned int. because it is for length, it will certainly not be negative. Therefore, unsigned integer is used, but it is also prone to bug s. Please see the following code:

Interpret the following code. What is the output result

#include<stdio.h>
#include<string.h>
 
int main()
{
	if (strlen("abc") - strlen("abcdef") > 0)
		printf(">");
	else
		printf("<=");
	return 0;
}

Yes, the answer is to output ">", why? 3 - 6 = - 3 duck, what's going on?

This is because the return value of strlen is size_t. It belongs to unsigned number, so if two unsigned numbers are subtracted, the answer must be unsigned number.

How to modify it?

Scheme 1: forced type conversion

#include<stdio.h>
#include<string.h>
 
int main()
{
	if ((int)strlen("abc") - (int)strlen("abcdef") > 0 )
		printf(">");
	else
		printf("<=");
	return 0;
}

Scheme 2: direct comparison

#include<stdio.h>
#include<string.h>
 
int main()
{
	if (strlen("abc") > strlen("abcdef"))
		printf(">");
	else
		printf("<=");
	return 0;
}

be careful:

  • String ends with '\ 0'. strlen returns the number of characters before '\ 0' in the string (excluding '\ 0');
  • The string pointed to in the parameter must end with '\ 0';
  • Note that the return value of the strlen function is size_t type, which belongs to unsigned type (especially error prone)

Code example:

#include<stdio.h>
#include<string>
 
int main()
{
    int len = strlen("abcdef");
	printf("%d\n", len);
 
	return 0;
}

Custom function simulation implementation strlen():

method:

  1. Counter method
  2. Recursive method
  3. Pointer pointer

Method 1: counter method

int my_strlen(const char* str)
{
	assert(str);//Assertion str is not null
	int count = 0;
	while (*str != '\0')
	{
		count++;
		str++;
	}
	return count;
}

Method 2: recursive method

int my_strlen(const char* str)
{
	assert(str);//Assertion str is not null
	//Find boundary
	if (*str == '\0')
	{
		return 0;
	}
	int count = my_strlen(str + 1);
	//Note that str + + and str+1 are different concepts
	count++;
	return count;
}

It should be noted here that str + + and str+1 are not the same concept. str + + is used first and then + +. This problem can be written in the form of + + str and used first and then + +.

Method 3: pointer pointer

Pointer - pointer actually represents the number of elements between two pointers. Note that there are not a few bytes in the middle.

int my_strlen(const char* str)
{
	assert(str);
	const char* cur = str;
	while (*cur != '\0')
	{
		cur++;
	}
	return cur - str;
}

2.strcpy()

Function prototype:

Function function:

Copy the source string to the target string and return the address of the first element of the target string.

Interpret the following codes:

#include<stdio.h>
#include<string.h>
 
int main()
{
	char arr1[] = "abcdef";
	char arr2[20] = { 0 };
	printf("%s\n", strcpy(arr2, arr1));
 
	return 0;
}

This problem is to copy the string arr2 to the string arr1, and return the address of the first element of arrr2 (the address of the first element of the target string). Therefore, the output of the above code is abcdef. The question here is whether the '\ 0' in the string arr1 will be copied to the string arr2. Therefore, the following code is used to verify this problem:

#include<stdio.h>
#include<string.h>
 
int main()
{
	char arr1[] = "abcdef";
	char arr2[20] = "XXXXXXXXXX";
	printf("%s\n", strcpy(arr2, arr1));
 
	return 0;
}

First, when the string arr1 has not been copied to arr2, the data they store is as follows:

After strcpy(arr2, arr1) is executed, the data stored in arr2 is as follows:

You can see that when copying the string arr1 (source string) to the string arr2 (target string), the '\ 0' at the end of the source string will be automatically copied, and the address of the starting position of the target string will be returned.

Another problem here is that if '\ 0' is not added at the end of the source string (this is demonstrated in the form of character array, and '\ 0' will be automatically filled at the end of the normal string), please see the following code:

#include<stdio.h>
#include<string.h>
 
int main()
{
	char arr1[] = { 'a','b','c','d','e','f' };
	char arr2[20] = "XXXXXXXXXX";
	
	printf("%s\n", strcpy(arr2, arr1));
	return 0;
}

Execution result code:

Therefore, it should be noted that if you want to copy the source string to the target string, you must ensure that the source string contains' \ 0 ', otherwise the copy will fail.

Therefore, you should pay attention to the following points when using strcpy to copy strings:

  • The source string must end with '\ 0';
  • When copying, the '\ 0' in the source string will be copied to the target string together;
  • The target string (target space) must be large enough to store the source string;
  • Another point is that the target string must be changeable

See the following code:

#include<stdio.h>
#include<string.h>
 
int main()
{
	char arr1[] = "abcdef";
	const char* p = "XXXXXXXXXX";
	printf("%s\n", strcpy(p, arr1));
	return 0;
}

The execution of the program is wrong, because the target string at this time is modified by const and cannot be modified.

User defined function simulation implementation strcpy()

Code execution:

char* my_strcpy(char* dest, const char* src)
{
	char* ret = dest;
	assert(dest && src);
	while (*dest++ = *src++)//Very good
	{
		;
	}
	return ret;
}

3.strcat()

Function prototype:

Function function:

Append the source string to the destination string and return the address of the first character of the destination string

Interpret the following codes:

#include<stdio.h>
#include<string.h>
 
int main()
{
	char arr1[30] = "hello";
	char arr2[] = "world";
 
	strcat(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

The above code splices "world" behind "hello", so the print results are as follows:

In fact, the precautions for using strcat library function are very similar to strcpy. I won't explain it again here:

  1. The source string must end with '\ 0';
  2. The target space must be large enough to accommodate the contents of the source string;
  3. The target space must be variable.

So imagine: if we let ourselves implement the strcat function, what should we do? First think about the general idea. First, we need to find the end flag '\ 0' of the target string, then splice the source string behind the target string, and finally return the address of the first character of the target string. It seems very simple. Let's implement:

User defined function simulation implementation strcat()

Code execution:

char* my_strcat(char* dest, const char* src)
{
	char* ret = dest;
	assert(dest && src);
	//1. Found target string \ 0
	while (*dest)//Note that it is wrong to write the loop condition as * dest + +, because \ 0 will be skipped. Please review it carefully
	{
		dest++;
	}
	//2. Copy source string
	while (*dest++ = *src++)
	{
		;
	}
	return ret;
}

4.strcmp()

Function prototype:

Function function:

Compare the dictionary order of the characters in the corresponding position

Standard provisions:

  • If the first string > the second string, a number greater than 0 will be returned;
  • If the first string = = the second string, 0 is returned;
  • If the first string < the second string, a number less than 0 is returned.

Knock on the blackboard:

The two strings cannot be compared directly, nor can they be added or subtracted directly, because the string represents the address of the first character. In other words, if you compare directly, the comparison is not the content of the string, but the address, so it is wrong.

User defined function simulation implementation strcmp()

Code execution:

int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);
	while (*str1 == *str2)//Notice that it is to judge the equality in the loop body, and think about why
	{
		if (*str1 == '\0')
			return 0;
		str1++;
		str2++;
	}
	if (*str1 > *str2)//return *str1 - *str2;
		return 1;
	else
		return -1;
}

5, Analog implementation of memory functions

1.memcpy()

Function prototype:

Note that the third parameter in the memory operation function is in bytes.

Think about why it's a void * type?

Because the designer does not know what type the library function will be used to copy when designing the library function, it is best to design it as void *.

Look at the following code:

#include<stdio.h>
#include<string.h>
 
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[5] = { 0 };
	memcpy(arr2, arr1 + 5, 5 * sizeof(arr1[0]));
 
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%d ", arr2[i]);
	 }
	return 0;
}

User defined function simulation implementation memcpy()

Code execution:

void* my_memcpy(void* dest, const void* src, size_t num)
{
	void* ret = dest;//Note that the return type is void *, not void,
	assert(dest && src);
	while (num--)//Use first, then--
	{
		*(char*)dest = *(char*)src;//Think about why cast type to char *, because only it is most appropriate
		dest = (char*)dest + 1;//Note that direct dest++,src + + is wrong because it is an empty type
		src = (char*)src + 1;
	}
	return ret;
}

2.memmove()

Function prototype:

In fact, C language only requires:

Memcpy can copy non overlapping memory space. Memmove handles those overlapping memory copies. That is, if the function of memcpy is A, the function of memmove is A+B

So what is overlapping memory copies? Please see the following code:

#include<stdio.h>
#include<string.h>
 
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	
	memmove(arr1 + 2, arr1, 5 * sizeof(arr1[0]));//Overlapping memory copies occur when processing the same space
 
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	 }
	return 0;
}

Implementation of memmove by user-defined function simulation

Code execution:

void* my_memmove(void* dest, const void* src, size_t num)
{
	void* ret = dest;
	assert(dest && src);
	if (dest < src)//Copy from front to back
	{
		while (num--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	else//Copy back to front
	{
		//src = (char*)src + num - 1;// Be sure to - 1
		//dest = (char*)dest + num - 1;
		//while (num--)
		//{
		//	*(char*)dest = *(char*)src;
		//	dest = (char*)dest - 1;
		//	src = (char*)src - 1;
		//}
		while (num--)//First use, then --, in the loop body is the num after -- (really wonderful)
		{
			*((char*)dest + num) = *((char*)src + num);
		}
	}
	return ret;
}

6, Meet Enron meet you, not negative code, not negative Qing.

Today's interview questions are here. The old fellow who has gained some trouble has moved his little hand to a three company. 🌹.

Topics: C Back-end