Detailed Explanation of Operators in C Language
Operators
//Arithmetic operators + - * / %
//Shift operators << >>
//Bitwise operators & | ^
//Assignment operators =
//Compound assignment operators += -= *= /= %= >>= <<= &= |= ^=
//Unary operators ! - + & sizeof ~ -- ++ * (type)
//Relational operators > >= < <= != ==
//Logical operators && ||
//Conditional operator exp1 ? exp2 : exp3
//Comma expression exp1, exp2, exp3, …expN
//Subscript reference [ ] subscript reference operator
//Function call ( ) function call operator
//Structure member . structure.member name -> structure pointer->member name
//Binary operators >> << & | ^ ~
%d is the decimal form to print a signed integer
%u is the decimal form to print an unsigned integer
//Give the compiler a number, %d,%u themselves take it as signed and unsigned, there is no need to look at whether the original variable is signed or unsigned.
%s is to print a string
%c is to print a character
%p is to print an address
%fl %f is to print a floating point number
% .2 lf is to retain two decimal places
% .3 lf is to retain three decimal places
Binary
In memory, for storing an integer, it needs 4 bytes, which is 32 bits.
When an integer is written as a binary sequence, it is 32 bits.
Signed integers: The highest bit is the sign bit. If the sign bit is 1, it represents a negative number. If the sign bit is 0, it represents a positive number.
Unsigned integers (unsigned int): There is no sign bit, all bits are valid bits.
Unsigned integers usually place positive numbers, representing positive numbers, so the original code, inverse code, and complement code are the same.
However, if a negative number is placed, it is calculated according to the original code, inverse code, and complemant code of the negative number. It does not hinder placing a negative number.
0: +0 and -0
In memory, the binary representation of an integer has three forms: original code, inverse code, and complement code.
For positive integers: original code, inverse code, and complement code are the same, no calculation needed.
For negative integers: original code, inverse code, and complement code need to be calculated.
Original code: the binary sequence directly written according to the positive or negative of the value is the original code.
Inverse code: the sign bit remains unchanged, and the other bits are flipped.
Complement code: add 1 to the inverse code's binary sequence to get the complement code.
The storage in memory of integers is the complement binary sequence.
The calculation of integers uses the complement binary sequence.
Conversion betwean original code, inverse code, and complement code:
The computer uses this line of thinking of flipping and then adding 1.
//10:
Original code: 00000000000000000000000000001010
Inverse code: 00000000000000000000000000001010
Complement code: 00000000000000000000000000001010
//-10
Original code: 10000000000000000000000000001010
Inverse code: 11111111111111111111111111110101
Complement code: 11111111111111111111111111110110
Arithmetic Operators
+ - * / %
- Except for the % operator, the other operators can be applied to both integers and floating-point numbers.
- For the / operator, if both operands are integers, it performs integer division. If there is a floating-point number, it performs floating-point division.
- The two operands of the % operator must be integers. It returns the remainder after the integer.
In the previous introduction to C language, we focused on / and %, here we will review again.
Integer Division
//Integer division
#include<stdio.h>
int main()
{
int m = 7 / 2;
int x = 7.0 / 2;
int y = 7.0 / 2.0;
double n = 7 / 2;
printf("m=%d\n", m);
printf("x=%d\n", x);
printf("y=%d\n", y);
printf("n=%f\n", n);
return 0;
}
Integer division: both ends of the operands can be integers or floating-point numbers.
The variable type that stores it can be integer or floating-point (floating-point numbers have decimal parts).
In printing, choose the corresponding character and variable type to align.
Floating Point Division
//Floating point division
#include<stdio.h>
int main()
{
double m = 7.0 / 2;
double b = 7 / 2.0;
double n = 7.0 / 2.0;
printf("m=%lf\n", m);
printf("b=%lf\n", b);
printf("n=%lf\n", n);
return 0;
}
Floating point division: both ends of the operand must have at least one as a floating-point number to get a floating-point result.
The floating-point operation should be stored in a floating-point variable.
The printed floating point requires the corresponding letter for the floating-point type.
Modulo (Remainder)
//Modulo
#include<stdio.h>
int main()
{
int n = 7%2;
printf("n=%d\n", n);
return 0;
}
Modulo (remainder):
Both operands must be integers.
The result should be stored in a integer variable.
Shift Operators
<< Left shift operator
>> Right shift operator
- Shift operators move binary bits
- The operands of shift operators must be integers
- Left shift operator >> shift rule: discard the left, fill with 0 on the right
- Right shift operator << shift rule:
Logical shift: fill with 0 on the left, discard on the right
Arithmetic shift: fill with the sign bit of the original value on the left, discard on the right
Do not shift by a negative number, this is undefined behavior according to the standard.
The application of shift operators: you can shift the desired bits to change the value.
<< Left Shift Operator
Positive Numbers
//Positive number
#include<stdio.h>
int main()
{
int m = 7;
int n = m << 1;
printf("%d\n", m);
printf("%d\n", n);
return 0;
}
The calculation is as follows:
Negative Numbers
//Negative number
#include<stdio.h>
int main()
{
int m = -7;
int n = m << 1;
printf("%d\n", m);
printf("%d\n", n);
return 0;
}
The calculation is as follows:
Summary
Left shift operator shift rules:
Discard the left, fill with 0 on the right. (Effect of multiplying by 2)
Integers in memory are in binary, calculated using the complement binary. Converted to decimal is the original code of the binary.
For positive numbers, original code, inverse code, and complement code are equal.
For negative numbers, inverse code and complement code require calculation.
>> Right Shift Operator
Positive Numbers
//Positive number
#include<stdio.h>
int main()
{
int a = 10;
int b = 10 >> 1;
printf("%d\n", a);
printf("%d\n", b);
return 0;
}
The calculation is as follows:
Negative Numbers
//Negative number
#include<stdio.h>
int main()
{
int a = -10;
int b = -10 >> 1;
printf("%d\n", a);
printf("%d\n", b);
return 0;
}
VS compiler uses arithmetic shift, most compilers use arithmetic shift!
Logical shift operations
Arithmetic shift operations
Summary
Right shift operator shift rules:
Logical shift: fill with 0 on the left, discard on the right. (Changes the sign of negative numbers, /2 effect)
Arithmetic shift: fill with the sign bit of the original value on the left, discard on the right. (/2 effect)
For positive numbers, logical and arithmetic shifts achieve the same effect of /2, the original code, inverse code, and complement code are equal without calculation.
For negative numbers, logical shift changes the sign, the shift does not change. Both have /2 effect, the original code, inverse code, and complement code need calculation.
Bitwise Operators
- & Bitwise AND
On the corresponding binary bits, if there is 0, it is 0, and both are 1 only when it is 1.
- | Bitwise OR
On the corresponding binary bits, if there is 1, it is 1, and both are 0 only when it is 0.
- ^ Bitwise XOR
On the corresponding binary bits, if they are the same, it is 0, and if they are different, it is 1.
The two operands of the bitwise operator must be integers.
The operation of the bitwise operator is performed on the complement binary.
& AND
//Calculate 3 & -5
//00000000 00000000 00000000 00000 011 //3 original code, complement code, inverse code
//10000000 00000000 00000000 00000 101 //-5 original code
//11111111 11111111 11111111 11111 010 //-5 inverse code
//11111111 11111111 11111111 11111 011 //-5 complement code
//00000000 00000000 00000000 00000 011 //3 original code, complement code, inverse code
//00000000 00000000 00000000 00000 011 //3 complement code, inverse code, original code
//& AND - On the corresponding binary bits, if there is 0, it is 0, and both are 1 only when it is 1
#include<stdio.h>
int main()
{
int a = 3;
int b = -5;
int c = a & b;
printf("%d", c);
return 0;
}
| OR
//Calculate 3 | -5
//00000000 00000000 00000000 00000 011 //3 original code, complement code, inverse code
//10000000 00000000 00000000 00000 101 //-5 original code
//11111111 11111111 11111111 11111 010 //-5 inverse code
//11111111 11111111 11111111 11111 011 //-5 complement code
//00000000 00000000 00000000 00000 011 //3 original code, complement code, inverse code
//11111111 11111111 11111111 11111 011 //complement code
//11111111 11111111 11111111 11111 010 //inverse code
//10000000 00000000 00000000 00000 101 //original code -5
//| OR - On the corresponding binary bits, if there is 1, it is 1, and both are 0 only when it is 0
#include<stdio.h>
int main()
{
int a = 3;
int b = -5;
int c = a | b;
printf("%d", c);
return 0;
}
^ XOR
//Calculate 3 ^ -5
//00000000 00000000 00000000 00000 011 //3 original code, complement code, inverse code
//10000000 00000000 00000000 00000 101 //-5 original code
//11111111 11111111 11111111 11111 010 //-5 inverse code
//11111111 11111111 11111111 11111 011 //-5 complement code
//00000000 00000000 00000000 00000 011 //3 original code, complement code, inverse code
//11111111 11111111 11111111 11111 000 //complement code
//11111111 11111111 11111111 11110 111 //inverse code
//10000000 00000000 00000000 00001 000 //original code -8
//Two important points
//a^a=0
//0^a=a
//Supports commutative law
//^ XOR - Same is 0, different is 1
#include<stdio.h>
int main()
{
int a = 3;
int b = -5;
int c = a ^ b;
printf("%d", c);
return 0;
}
Exercise
Without creating a temporary variable (third variable), exchange two numbers.
Write code to find the number of 1s in the binary representation of an integer stored in memory. (Later explanation, you can try writing it first.)
//Without creating a temporary variable (third variable), exchange two numbers
In the previous introduction to C language and functions, we already know the following methods:
//Create a temporary variable
#include<stdio.h>
int main()
{
int a = 3;
int b = 5;
int c = 0;//Create intermediate variable
printf("a=%d b=%d\n", a, b);
c = a;
a = b;
b = c;
printf("a=%d b=%d", a, b);
return 0;
}
//Function
#include<stdio.h>
void change(int* a, int* b)
{
int tmp = 0;
tmp = *a;
*a = *b;
*b = tmp;
}
int main()
{
int a = 3;
int b = 5;
printf("a=%d b=%d\n", a, b);
change(&a,&b);
printf("a=%d b=%d", a, b);
return 0;
}
What if we don't create a temporary variable?
#include<stdio.h>
int main()
{
int a = 3;
int b = 5;
printf("a=%d b=%d\n", a, b);
a = a + b;
b = a - b;//b=a+b-b=a
a = a - b;//a=a+b-a
printf("a=%d b=%d", a, b);
return 0;
}
This addition and subtraction method has a flaw, the value of the variable may be too large and cause overflow. Is there any other way?
#include<stdio.h>
int main()
{
int a = 3;
int b = 5;
printf("a=%d b=%d\n", a, b);
a = a ^ b;//3^5
b = a ^ b;//3^5^5=3
a = a ^ b;//3^5^3=5 (supports commutative law)
printf("a=%d b=%d", a, b);
return 0;
}
The above XOR method
Advantages: no overflow.
Disadvantages: low efficiency, only applicable to integers, poor readability, thus not recommended for use.
Assignment Operators
The assignment operator is a great operator! 😊😊 After the variable is created, we modify it to the value we like.
#include<stdio.h>
int main()
{
int a = 3;//not assignment but initialization
a = 4;//assignment
return 0;
}
Continuous Assignment
The assignment operator can be used continuously, as follows:
#include<stdio.h>
int main()
{
int a = 10;
int x = 0;
int y = 20;
a = x = y + 1;//continuous assignment, assign from right to left
return 0;
}
Continuous assignment shortens the code and achieves conciseness. However, its readability is very poor, making it difficult to debug. It is recommended to separate them.
//Continuous assignment
a=x=y+1;
//Non-continuous is more clear
x = y+1;
a = x;
Compound Assignment
#include<stdio.h>
int main()
{
int a = 10;
a = a << 1;
a <<= 1;
int b = 7;
b = b >> 1;
b >>= 1;
return 0;
}
Unary Operators
Unary operators refer to those with only one operand.
- ! Logical negation operator
- Negative value
- Positive value
- & Address-of operator
- sizeof Size of the operand's type (in bytes)
- ~ Bitwise negation of a number
- -- Pre-increment, post-increment
- ++ Pre-increment, post-increment
- Indirect access operator (dereference operator)
- (type) Type casting
!
! Logical negation operator:
Turns true into false, and false into true.
//!
#include<stdio.h>
int main()
{
int a = 0;
int flag = !a;
printf("%d\n", flag);
if (!a)//Expression is true, print
{
printf("haha\n");
}
return 0;
}
- and +
- Positive: has no specific meaning.
- Negative: changes the sign of the value. Positive becomes negative, negative becomes positive.
//+ -
#include<stdio.h>
int main()
{
int a = 10;
printf("%d\n", a);
a = +a;
printf("%d\n", a);
a = -a;
printf("%d\n", a);
int b = -10;
printf("%d\n", b);
b = +b;
printf("%d\n", b);
b = -b;
printf("%d\n", b);
return 0;
}
& and *
& Address-of: int* p=&a; (needs to be stored in a pointer variable)
- Dereference operator:
*p performs dereference operation on p, *p finds the object pointed to by p through the address stored in p. *p is actually a.
#include<stdio.h>
int main()
{
int a = 10;
int* p = &a;//Address of a variable
printf("%p\n", &a);
printf("%d", *p);//*p=a
int arr[10] = {1,2,3,4,5};
int(*pa)[10] = &arr;//Address of array
return 0;
}
sizeof
sizeof calculates the size of a type or variable, measured in bytes.
The result of sizeof is of type size_t.
When the parentheses do not contain a type, the parentheses can be omitted. This indicates that sizeof is not a function.
sizeof is an operator (unary operator), not a function. Functions cannot omit parentheses.
When calculating the number of elements in a string array, include "\0".
size_t is an unsigned integer type.
When printing data of type size_t, use %zd.
//sizeof
#include<stdio.h>
#include<string.h>
int main()
{
int a = 10;
printf("%d\n", sizeof(a));
printf("%d\n", sizeof(int));
printf("%d\n", sizeof a);//4
int arr[10] = { 0 };
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr[0]));
printf("%d\n", sizeof(arr) / sizeof(arr[0]));
char arr1[] = "abcde";
printf("%d\n", sizeof(arr1));
printf("%d\n", strlen(arr1));
return 0;
}
~
~ Inverts the binary of a number.
#include<stdio.h>
int main()
{
int a = 0;
printf("%d", ~a);
return 0;
}
//00000000 00000000 00000000 00000000
//11111111 11111111 11111111 11111111 complement code
//11111111 11111111 11111111 11111110 inverse code
//10000000 00000000 00000000 00000001 original code -1
-- and ++
- Pre-increment: increment by 1 first, then use
- Post-increment: use first, then increment by 1
- Pre-decrement: decrement by 1 first, then use
- Post-decrement: use first, then decrement by 1
- ++ operator is an increment-by-1 operation
- -- operator is a decrement-by-1 operation
(Who is in front, perform what operation first)
A rule of post-increment: pre-assignment operation.
*dest++ = *src++
Two pointers first use * and =, then ++
#include<stdio.h>
//++ Pre-increment Post--
//-- Pre-decrement Post--
int main()
{
int a = 7;
int b = a++;//Post-increment a++ Rule: Use first, then increment by 1
//Equivalent to b=a a=a+1
printf("a=%d b=%d\n",a,b);//8 7
return 0;
}
int main()
{
int a = 7;
int b = ++a;//Pre-increment a Rule: Increment by 1 first, then use
//Equivalent to a=a+1 b=a
printf("a=%d\n", a);//8
printf("b=%d\n", b);//8
return 0;
}
int main()
{
int a = 7;
int b = a--;//Post-increment a-- Rule: Use first, then decrement by 1
//Equivalent to b=a a=a-1
printf("a=%d b=%d\n",a,b);//6 7
return 0;
}
int main()
{
int a = 7;
int b = --a;//Pre-decrement a Rule: Use first, then decrement by 1
//Equivalent to a=a-1 b=a
printf("a=%d b=%d\n",a,b);//6 6
return 0;
}
(type)
(type) Type conversion
Avoid using it unless necessary. The forced gourd is not sweet. It is best to set variables with matching types.
#include<stdio.h>
int main()
{
int a = (int)3.14;
//3.14 is recognized by the compiler as a double type
//time_t——>unsigned int
srand((unsigned int)time(NULL));
rand();
//Generate random number
return 0;
}
Exercise
#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;
}
//Question:
//Where (1) and (2) output how much? 40 10
//Where (3) and (4) output how much? 4 4/8 8
- (1) sizeof(arr) calculates the total size of the arr array. The array contains 10 elements of integers. One integer is 4 bytes, so it is 40.
- (2) sizeof(ch) calculates the total size of the ch array. The array contains 10 elements of characters. One character is 1 byte, so it is 4.
- (3) test1 and test2 function calls, pass arr over, essentially passing the address of the array, pointer receives. Whether it is an integer or a character pointer, it is a pointer variable (address), and the sizes are equal. (4/8)
Pointer variables are used to store addresses.
Pointer variable size depends on how much space is needed to store an address.
In a 32-bit environment:
An address is 32 bits, requiring 4 bytes. So regardless of the type of pointer variable, the size is 4 bytes.
In a 64-bit environment:
An address is 64 bits, requiring 8 bytes. So regardless of the type of pointer variable, the size is 8 bytes.
In summary: the size of a pointer is 4 bytes in a 32-bit platform and 8 bytes in a 64-bit platform.
Don't look at pointers through a keyhole, and don't flatten your view of pointers. No matter what type of pointer it is, it is 4/8 bytes.
Relational Operators
These relational operators are used to test the size relationship between the two operands.
Especially note: in programming, == and = are accidentally written incorrectly, leading to errors. (Differentiate)
Logical Operators
- && Logical AND and: if one operand is false, the result is false. Only if both are true, the result is true.
- || Logical OR or: if one operand is true, the result is true. Only if both are false, the result is false.
#include<stdio.h>
int main()
{
//3~5 months spring
int a = 0;
scanf("%d", &a);
if (a >= 3 && 5 >= a)
printf("spring");
//12 or 1 or 2 are winter
if (a == 12 || a == 1 || a == 2)
printf("winter");
return 0;
}
There is also a practice question, try to write it yourself.
#include <stdio.h>
int main()
{
int i = 0,a=0,b=2,c =3,d=4;
i = a++ && ++b && d++;
printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
return 0;
}
#include <stdio.h>
int main()
{
int i = 0,a=0,b=2,c =3,d=4;
i = a++||++b||d++;
printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
return 0;
}
//What are the results of the program?
//Tip: && If the left operand is false, the right operand does not need to be calculated.
// || If the left operand is true, the right operand does not need to be calculated.
If the initial value of a is changed to 1, what will the result be? (Later explanation of operator questions okay okay)
Conditional Operator
exp1?exp2:exp3
Three operands, a ternary operator
Rewrite the following two pieces of code using the conditional operator.
//Exercise 1
#include<stdio.h>
int main()
{
int a = 0;
int b = 0;
scanf("%d", &a);
if (a > 5)
b = 3;
else
b = -3;
printf("%d", b);
return 0;
}
//Exercise 2
#include<stdio.h>
int main()
{
int a = 0;
int b = 0;
int m = 0;
scanf("%d %d", &a,&b);
if (a > b)
m = a;
else
m = b;
printf("%d", m);
return 0;
}
After modification
//Exercise 1
#include<stdio.h>
int main()
{
int a = 0;
int b = 0;
scanf("%d", &a);
b = (a > 5 ? 3 : -3);
printf("%d", b);
return 0;
}
//Exercise 2
#include<stdio.h>
int main()
{
int a = 0;
int b = 0;
int m = 0;
scanf("%d %d", &a, &b);
m = (a > b ? a : b);
printf("%d", m);
return 0;
}
Comma Operator
exp1,exp2,exp3,.......expN
Comma expression, separated by commas.
Comma expression, executed from left to right. (Each expression is calculated in order, the previous expression affects the next one).
The result of the entire expression is the result of the last expression.
//Exercise 1
int a = 1;
int b = 2;
int c = (a>b, a=b+10, a, b=a+1);//comma expression
What is the value of c?
//13
//Exercise 2
a = get_val();
count_val(a);
while (a > 0)
{
//business processing
a = get_val();
count_val(a);
}
//Rewrite as comma expression
//If using comma expression, rewrite:
while (a = get_val(), count_val(a), a>0)
{
//business processing
}
Note: do not calculate the previous expressions just because the last expression plays a decisive role. The previous expressions may affect the last expression.
Subscript Reference, Function Call, and Structure Member
Subscript Reference
[ ] Subscript reference operator
Operands: an array name and an index value.
#include<stdio.h>
int main()
{
int arr[5] = { 1,2,3,4,5 };
// 0 1 2 3 4 index value
printf("%d", arr[2]);//Operands arr and 2
return 0;
}
Function Call
( ) Function call operator
Accepts one or more operands. The first operand is the function name, and the remaining operands are the parameters passed to the function. (The function call operator has at least one operand)
#include <stdio.h>
void test1()
{
printf("hehe\n");
}
void test2(int a,int b)
{
printf("%d\n", a+b);
}
int main()
{
test1();
test2(3,5);//Use ( ) as the function call operator.
return 0;
}
Structure Member
. Structure.member name
-> Structure->member name
#include<stdio.h>
struct Book
{
char name[20];
int price;
};
void Print(struct Book* pb)//Structure pointer variable
{
printf("%s %d\n", (*pb).name, (*pb).price);
printf("%s %d\n", pb->name, pb->price);
}
int main()
{
struct Book b = { "C language",55 };
printf("%s %d\n", b.name, b.price);
Print(&b);
return 0;
}
✔✔✔✔Finally, thank you for reading, any errors and shortcomings are welcome to point out!!
Code-------------------→【gitee:https://gitee.com/TSQXG】
Contact--------------------→【Email: 2784139418@qq.com】