content
3.1 A perverted interview question
3.2 Classic interview questions (requires attention)
8. Conditional operator (ternary operator)
10. Subscript references, function calls, and structure members
10.1 [ ]: Subscript Reference Operator
10.2 ( ): function call operator
10.3 Accessing members of a structure
11.1 Implicit type conversions
1. Arithmetic operator
+ - * / %
Note:
1. In addition to the % operator , several other operators can act on integers and floating-point numbers.
2. For the / operator If both operands are integers , perform integer division . And as long as there are floating -point numbers, floating-point division is performed .
3. The two operands of the % operator must be integers . Returns the remainder after division .
void test1()
{
//6.0 % 2.0; //不是整型,err
int a= 6 / 2;
int b = 7 / 2;
double c = 7 / 2.0;
printf("a = %d b = %d c = %lf", a, b,c);//a=3 b=3 c=3.500000
}
2. Shift operator
<< left shift operator
>> right shift operator
Note: The operands of the shift operator can only be integers.
2.1 Left shift operator
moving bits
Shifting rules: discard on the left, add 0 on the right
void test2()
{
int a = 7;//a是一个int变量,4个字节,32个bit位
int b = a << 1;
printf("b = %d\n", b); //14
}
2.2 Right shift operator
Shift rules:
First, there are two types of right shift operations:
1. Logical shift : fill with 0 on the left , discard on the right
2. Arithmetic shift : fill the left side with the original sign bit and discard the right side (the original positive number is filled with 0, otherwise it is filled with 1)
Supplement: When integers are stored in memory, they are stored in binary, and there are three representations:
Original code, inverse code, complement code
For -1:
10000000000000000000000000000001 original code
1111111111111111111111111111110 Complement code (sign bit remains unchanged, other bits are inverted bit by bit)
11111111111111111111111111111111's complement (one's complement + 1)
For integers, the computer is stored in two's complement form
for int b = -1;
It can be seen that the binary of -1 is 11111111111111111111111111111111 => complement form
void test3()
{
int a = 1;
int b = -1;
int c = a >> 1;
int d = b >> 1;
//b从11111111111111111111111111111111
//=> 11111111111111111111111111111111
printf("c = %d d = %d\n", c, d); //c = 0,d = -1 说明此时编译器用的是算数右移
}
Warning ⚠: For shift operators, do not shift negative bits, this is undefined by the standard. E.g:
int num = 10;
num>>-1;//error
3. Bitwise operators
Bit operators are:
& : bitwise AND: the result of 0 is 0, and the result is 1 when all are 1
| : bitwise OR: the result of 1 is 1, and the result is 0 when all are 0
^ : Bitwise exclusive OR: the corresponding binary bits, the same is 0 and the difference is 1
Note: their operands must be integers .
void test4()
{
int a = 3;
int b = 5;
int c = a & b; // & - 按(二进制)位与 - 有0结果就是0,全为1时结果为1
//a:011
//b:101
//c:001
int d = a | b; // | - 按(二进制)位或 - 有1结果就是1,全为0时结果为0
//a:011
//b:101
//d:111
int e = a ^ b; // ^ - 按(二进制)位异或 - 对应的二进制位,相同为0相异为1
//a:011
//b:101
//e:110
printf("c = %d d = %d e = %d", c, d, e); //c = 1 d = 7 e = 6
}
3.1 A perverted interview question
A temporary variable (the third variable) cannot be created to exchange two numbers.
void test5()
{
int a = 3; //011
int b = 5; //101
a = a ^ b; // a = 110
b = a ^ b; // b = 011
a = a ^ b; // a = 101
printf("a = %d b = %d\n", a, b); //a = 5 b =3
}
Conclusion: a ^ b ^ a = b, b ^ a ^ b = a, a ^ a = 0, 0 ^ a = a
(In a^b^a: a and a cancel out to get b, and the conclusion conforms to the "commutative law", that is, a^a^b = b, and the XOR result of two identical numbers is 000)
3.2 Classic interview questions (requires attention)
Write code to achieve: find the number of 1's in binary stored in an integer in memory
//方法一
int count_one1(int n)//该方法存在缺陷,计算负数会出错
{
int count = 0;
while (n) //只要不是0 二进制序列中就会有1
{
if (n % 2 == 1)
{
count++;
}
n = n / 2;
}
return count;
}
//方法二
//当a与1按位与:
//11111111111111111111111111111111
//00000000000000000000000000000001
//00000000000000000000000000000001
//可见:1的最后一位数字与a的最后一位保持一致
//所以判断一次就右移一次a,每次都与1相与 总共右移32次
int count_one2(int n)
{
int count = 0;
int i = 0;
for (i = 0; i < 32; i++)
{
if ( ( (n >> i) & 1 ) == 1 )
{
count++;
}
}
return count;
}
//方法三(最好的办法)
//n = n & (n-1) 假设n = 7
// 111 & 110 = 110
//再来一次:
//n = n & (n-1)
// 110 100 = 100
//结论:n = n & (n-1) 把n的二进制中从右向左的第一个1变成了0
//方法三的具体步骤为 : 在n = 0之前,不停地用n = n & (n-1),执行了几次,则有多少个1
int count_one3(int n)
{
int count = 0;
while (n != 0)
{
n = n & n - 1;
count++;
}
return count;
}
void test6()
{
int a = -1;
int ret = count_one3(a);
printf("%d\n", ret);
}
Summarize:
1.a & 1, the purpose that can be achieved is: the last digit of 1 is consistent with the last digit of a, so with the right shift operation of a, you can calculate how many 1s exist in binary
2. n = n & (n-1), this method changes the first 1 from right to left in the binary of n to 0, with the loop: before n = 0, keep using n = n & (n-1), if the loop is executed several times, how many 1s are there
4. Assignment operator
void test7()
{
int a = 0;
a = 3; //赋值操作符
}
The assignment operator can be used consecutively (but not recommended):
void test8()
{
int a = 10;
int x = 0;
int y = 20;
a = x = y + 1;//连续赋值
printf("a = %d\n", a); //a = 21
}
do x = y + 1 first, then a = x
Compound assignment operators : +=, -=, *=, /=, %=, >>=, <<=, &=, |=, ^= These operators can be written as compound effects. Such as:
int x = 10;
x = x+10;
x += 10;//复合赋值
//其他运算符一样的道理。这样写更加简洁。
Exercise: The binary digits of 14 are known to be: 000000000000000000000000000001110
Now let the 0 in the 5th last digit become 1, and then turn it into 0 after implementation
Idea: If you want the i-th bit from right to left to change from 0 to 1 , and the remaining bits remain unchanged, then let the original binary sequence and only the last i-th bit is 1, and the rest of the bits are all 0. The binary sequence phase OR operation is as follows:
Sequence a: 00000000000000000000000000001110
Sequence b: 0000000000000000000000000010000 Sequence b is obtained by shifting 1 to the left by 4 (i-1) units
Phase or: ----------------------------------------------- -------
Sequence c: 00000000000000000000000000011110
And if you want to change from sequence c back to a, that is, the method of changing the penultimate 5th bit from 1 to 0 : let the sequence c and the sequence d except the penultimate 5th bit is 0, and the rest of the bits are all 1 .
Sequence c: 00000000000000000000000000011110
Sequence d: 1 1 11 1 1 1 1111111111111111111101111
Phase and: --------------------------------------------------------- -------
Sequence a: 00000000000000000000000000001110
It is not difficult to see that the sequence d is obtained by the bitwise inversion of the sequence b
So the code is as follows:
void test10()
{
int a = 14;
a |= (1 << 4);
printf("%d\n", a); //30
a &= (~(1 << 4));
printf("%d\n", a); //14
}
5. Unary operator
! Logical inverse operation
- negative value
+ positive value
& take address sizeof operand type length in bytes
~ Reverse the binary bitwise of a number
-- Front, Rear--
++ pre, post ++
* Indirect access operator (dereference operator)
(type) cast
void test9()
{
3 + 5; // +有两个操作数 双目操作符
//单目操作符:只有一个操作数的操作符
//!操作符
int a = 10;
printf("a = %d\n", a); //10非0 - 真
printf("!a = %d\n", !a);//0
int flag = 1;
if (!flag)
{
//表示当flag为假的时候执行if语句
}
//&与*操作符 取地址与解引用
int b = 10;
int* pb = &b; //pb为指针变量,b的地址存在pa中
*pb = 20; //解引用操作 通过*pb访问或修改b的值
printf("b = %d\n", b); //20
//sizeof操作符 而不是函数! 还可以计算数组总大小
int c = 10;
int arr[10] = { 0 };
printf("sizeof(c) = %d\n", sizeof(c)); //4
printf("sizeof(int) = %d\n", sizeof(int)); //4
printf("sizeof(arr) = %d\n", sizeof(arr)); //40
printf("sizeof(int[10]) = %d\n", sizeof(int[10]) ); //40
// ~操作符 按位取反
int d = 0;
printf("d = %d\n", ~d); //-1
//00000000000000000000000000000000 //d的补码
//11111111111111111111111111111111 //按位取反后的补码
//11111111111111111111111111111110 //反码 (补码-1)
//10000000000000000000000000000001 //源码 (符号位不变,其他按位取反)
//-1
//(强制类型转换)
double e = 3.14;
printf("e = %d\n", (int)e); // e = 3
}
5.2 sizeof and arrays
#include <stdio.h>
void test1(int arr[])
{
printf("%d\n", sizeof(arr));//(2)
}
void test2(char ch[])
{
printf("%d\n", sizeof(ch));//(4)
}
int main()
{
int arr[10] = {0};
char ch[10] = {0};
printf("%d\n", sizeof(arr));//(1)
printf("%d\n", sizeof(ch));//(3)
test1(arr);
test2(ch);
return 0;
}
ask:
(1), (2) How much is the output of the two places? Answer: 40 10
(3) and (4) How much are the outputs of the two places? Answer: 4 4 (note)
Note: what is passed into test2 is the pointer of the first element of the ch array, which is 4 or 8 bytes, and should not be understood as the size of the first element of ch 1
5.3 ++ and -- operators
void test11()
{
int a = 10;
int b = 10;
int c = a++; //后置++:先使用再自增1
int d = ++b; //前置++ 先自增1后使用
printf("c = %d d = %d a = %d b = %d \n", c, d, a, b);//10 11 11 11
/*int e = 10;
int f = e + 1; //1
f = ++e; //带有副作用 - e变成了12*/
int g = 1;
printf("%d\n", g++); // 1
printf("%d\n", ++g); // 3
}
Example Question: What is the result of the following code?
#include <stdio.h>
int main()
{
int a, b, c;
a = 5;
c = ++a;
b = ++c, c++, ++a, a++;
b += a++ + c;
printf("a = %d b = %d c = %d\n:", a, b, c);// a = 9 b = 23 c = 8
return 0;
}
6. Relational Operators
>
>=
<
<=
!= is used to test for "not equal"
== is used to test for "equality"
These relational operators are relatively simple, but we need to be aware of the error-prone use of some operators :
1. In the process of programming, == and = are accidentally written incorrectly, resulting in errors
2. Strings cannot be compared directly with ==, and objects cannot be judged for equality with ==
3. When judging, you can't directly use connection, such as: 1<a<7 but should be a>1 && a<7 (if you use if(1<a<7), when a=8, it will first judge 1<8 ?, is true, continue to judge 1<7?, is true, so the whole expression is true, the content of the if statement will be executed and cause an error)
7. Logical Operators
&& logical AND
|| logical or
Distinguish between logical AND and bitwise AND , and distinguish between logical OR and bitwise OR
void test1()
{
int a = 2; //010
int b = 5; //101
int c = a & b; //按(2进制)位与:000
int d = a && b; //逻辑与:1
printf("c = %d d = %d\n", c, d);//0 1
int e = a | b; //按(2进制)位或:111
int f = a || b; //逻辑或:1
printf("e = %d f = %d\n", e, f);//7 1
}
Interview questions:
void test2()
{
//程序输出的结果是什么?
int i = 0, a = 0, b = 2, c = 3, d = 4;
i = a++ && ++b && d++; //a=1 b=2 c=3 d=4
//i = a++||++b||d++; //a=1 b=3 c=3 d=4
printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
}
Note: When using && to judge (a && b), when a is already false, the compiler will no longer judge whether b is true or false, because the result must be false
Similarly, when using || to judge (a || b), when b is already false, the compiler will no longer judge whether b is true or false, because the result must be true
8. Conditional operator (ternary operator)
expression1 ? expression2 : expression3
If expression1 is true, the result of the entire expression is the result of expression2, if it is false, the result of the entire expression is the result of expression3
void test3()
{
int a = 10;
int b = 20;
int max = 0;
max = a > b ? a : b;
printf("max = %d", max);
}
//上述代码等价于:
void test3()
{
int a = 10;
int b = 20;
int max = 0;
if (a > b)
max = a;
else
max = b;
printf("max = %d", max);
}
9. Comma Expression
expression1, expression2, expression3...expressionn
Comma expressions are multiple expressions separated by commas. Comma expressions, executed in order from left to right. The result of the entire expression is the result of the last expression.
Note: The result of the previous expression may affect the last expression, so you can't just look at the last expression and ignore the previous ones
void test4()
{
//代码1
int a = 1;
int b = 2;
int c = (a > b, a = b + 10, a, b = a + 1);
int d = 0;
printf("c = %d", c); //13
//代码2
if (a = b + 1, c = a / 2, d > 10);
//该表达式最终以d>10的真假做判断
//代码3
a = get_val();
count_val(a);
while (a > 0)
{
//业务处理
a = get_val();
count_val(a);
} //该代码较为冗余
//如果使用逗号表达式,改写:
while (a = get_val(), count_val(a), a > 0)
{
//业务处理
}
//判断条件仍是a>0,但前面的代码依旧会进行,该代码看起来更为简洁
}
10. Subscript references, function calls, and structure members
10.1 [ ]: Subscript Reference Operator
The operands are: 1. Array name 2. Index value
void test5()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };
arr[4]; //下标引用操作符
//系统会把arr[4] ==> *(arr + 4)
printf("%d\n", *(arr + 4)); //5 注:整型指针+1 地址跳过4个字节
printf("%d\n", arr[4]); //5
printf("%d\n", 4[arr]); //5 说明数组名和索引值可以互换位置
}
10.2 ( ): function call operator
int test6()
{
printf("hehe"); //函数调用操作符,即便没有传参也不能省略( )
}
10.3 Accessing members of a structure
.struct.membername
-> Structure pointer -> member name
void test7()
{
struct Book
{
char name[20];
int price;
};
struct Book b = {"C语言程序设计", 35};
//结构体变量.成员变量
printf("书名:%s 定价:%d\n", b.name, b.price);
struct Book* pb = &b;
//结构体指针->成员变量
printf("书名:%s 定价:%d\n", pb->name, pb->price);
}
11. Expression evaluation
The order in which expressions are evaluated is determined in part by the precedence and associativity of operators .
Likewise, the operands of some expressions may need to be converted to other types during evaluation .
11.1 Implicit type conversions
C integer arithmetic operations are always performed with at least the precision of the default integer type.
To achieve this precision, character (char) and short integer (short) operands in expressions are converted to ordinary integer types before use . This conversion is called integer promotion .
The integer operation of the expression should be performed in the corresponding operation device of the CPU. The byte length of the operand of the integer arithmetic unit (ALU) in the CPU is generally the byte length of the int, and it is also the length of the general-purpose register of the CPU.
Therefore, even the addition of two char types is actually converted to the standard length of the integer operand in the CPU when the CPU is executed.
It is difficult for general-purpose CPUs to directly add two 8-bit bytes directly (although there may be such byte addition instructions in machine instructions). Therefore, various integer values whose length may be less than the length of int in the expression must be converted to int or unsigned int before they can be sent to the CPU to perform operations.
How to improve overall?
Integer promotion is promoted according to the sign bit of the data type of the variable
//负数的整形提升
char c1 = -1;
变量c1的二进制位(补码)中只有8个比特位:
1111111
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为1
提升之后的结果是:
11111111111111111111111111111111
//正数的整形提升
char c2 = 1;
变量c2的二进制位(补码)中只有8个比特位:
00000001
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为0
提升之后的结果是:
00000000000000000000000000000001
//无符号整形提升,高位补0
Examples of shaping lifts:
void test8()
{
char a = 3;
char b = 127;
char c = a + b;
//a和b要发生整型提升
//3的二进制: 00000000000000000000000000000011
//把3存入a中,此时的a:00000011,由于最高位为0,正数
//所以a整形提升为:00000000000000000000000000000011 -提升后的a
//127的二进制: 00000000000000000000000001111111
//存入b中后: 01111111
//整形提升后: 00000000000000000000000001111111 -提升后的b
// + 00000000000000000000000000000011
//a+b 00000000000000000000000010000010
//存入c中:10000010
//打印%d的c - 又要发生整形提升
//此时打印的c: 11111111111111111111111110000010 -提升后的c - 补码
// 11111111111111111111111110000001 - 反码
// 10000000000000000000000001111110 - 原码 -126
printf("c = %d\n", c); //-126
}
void test9()
{
char a = 0xb6; //10110110
short b = 0xb600; //1011011000000000
int c = 0xb6000000; //101101100000000000000000
if (a == 0xb6)
printf("a");
if (b == 0xb600)
printf("b");
if (c == 0xb6000000)
printf("c");
//c
}
void test10()
{
char c = 1;
printf("%u\n", sizeof(c)); //1
printf("%u\n", sizeof(+c)); //4 +c是表达式,会发生整形提升(变成int 4字节)
printf("%u\n", sizeof(-c)); //4 与+c同理
}
11.2 Arithmetic conversions
If the operands of an operator are of different types, the operation cannot proceed unless one of the operands is converted to the type of the other. The following hierarchy is called ordinary arithmetic transformations .
long double
double
float
unsigned long int
long int
unsigned int
int
If the type of an operand is lower in the above list, the operation is performed first by converting to the type of the other operand. (For example: adding int and long int will convert int to long int)
But the arithmetic conversion should be reasonable , otherwise there will be some potential problems:
float f = 3.14;
int num = f;//隐式转换,会有精度丢失
Example: Find the result of the following code
#include <stdio.h>
int i; //全局变量 - 默认初始化为0
int main()
{
i--;
if (i > sizeof(i))
{
printf(">\n");
}
else
{
printf("<\n");
}
return 0;
}
The output is: >
Analysis: For the expression i > sizeof(i), i is of type int, and sizeof(i) is of type unsigned int. At this time, arithmetic conversion will occur , i will be converted to unsigned int type , i = -1 before arithmetic conversion, In memory, it is: 1111111111111111111111111111. At this time, the sign bit (highest bit) of the binary sequence is 1, indicating that it is a negative number. After converting to an unsigned integer, the highest bit is also a valid number, and i becomes a very large integer, so sure more than 4
11.3 Attributes of Operators
1. Operator precedence
2. Operator associativity
3. Whether to control the evaluation order
Some problem expressions:
表达式的求值部分由操作符的优先级决定。
表达式1
a*b + c*d + e*f
Note: When code 1 is calculated, since * has a higher priority than +, it can only be guaranteed that the calculation of * is earlier than +, but the priority does not determine that the third * is executed earlier than the first +.
So the computer order of the expression might be:
a*b
c*d
a*b + c*d
e*f
a*b + c*d + e*f
or:
a*b
c*d
e*f
a*b + c*d
a*b + c*d + e*f
表达式2
c + --c;
Note: Note: The same as above, the priority of the operator can only determine that the operation of the decrement-- is in front of the operation of +, but we have no way to know whether the left operand of the + operator is obtained before the right operand. It is evaluated later, so the result is unpredictable and ambiguous. Assuming c = 1, then the calculation order may be 1 + 0 = 1, or 0 + 0 = 0
//问题代码3
int fun()
{
static int count = 1;
return ++count;
}
int main()
{
int answer;
answer = fun() - fun() * fun();
printf( "%d\n", answer);//输出多少?
return 0;
}
Although the result is the same on most compilers. But in the above code answer = fun() - fun() * fun(); we can only know by the priority of the operators: first multiply, then subtract. , the calling sequence of functions cannot be determined by the precedence of operators.
//问题代码4
#include <stdio.h>
int main()
{
int i = 1;
int ret = (++i) + (++i) + (++i);
printf("%d\n", ret); //12 4 + 4 + 4
printf("%d\n", i); //4
return 0;
}
But the output result under linux system is ret = 10(3+3+4), i = 4
Summary: If the expression we write cannot determine the unique calculation path through the properties of the operator, then the expression is problematic.