C語言基礎

常量和常量表達式的區別

#define N 4;又是常量,又是常量表達式,其在編譯期預處理階段就會直接替換
const int M = 5;只是常量,不是常量表達式 ,其是存儲在一塊內存區域之內的,但是存儲的值不能改變
常量表達式:在編譯期間就可以直接求值的表達式
常量:在運行期間不能改變的
常量表達式可以用于指定數組長度,還可以用于switch語句的標簽

#define N 5
const int M = 4;
int main() {int arr[N];//正確int arr[M];//錯誤,M不是常量表達式int i;scanf("%d",&i);switch (i) {case N://正確printf("N = %d\n",N);break;case M://錯誤,M不是常量表達式printf("M =  %d\n",M);break;}
}

標準輸入輸出
在這里插入圖片描述
scanf本質上是一個“模式匹配函數”,試圖把輸入的字符與轉換說明進行匹配,從左到右一次處理轉換說明,如果成功,則繼續處理后面的字符串,如果失敗,則立即返回,返回值表示處理轉換說明成功的個數

int main() {int i,f;int k = scanf("%d %d",&i,&f);//輸入的必須為int類型float d;//盡量避免下面這種寫法k = scanf("i = %d,d = %f",&i,&d);//輸入格式必須為--- i = 17,d = 3,1415---這樣的格式,否則字符串匹配不上也我無法輸入return 0;
}

轉換說明:
(1)表示匹配的規則
(2)表示將字符數據轉換成對應的二進制數據

格式串:普通字符,其他字符(精確匹配),空白字符(匹配任意多個空白字符,包括零個)

注意事項:
scanf匹配%d,%f(進行數值匹配的時候,會匹配前面的空白字符)

讀寫整數
%u 無符號十進制整數
%o 無符號八進制整數
%x 無符號十六進制整數
%d 有符號十進制整數
讀寫短整數,在u,o,x,d前面添加h(short)
讀寫長整數,u,o,x,d前面添加l
讀寫長長整形,在u,o,x,d前面添加ll

int main() {unsigned a;scanf("%u",&a);printf("%u\n",a);printf("%o\n",a);printf("%x\n",a );short s;scanf("%hd",&s);printf("%hd",s);
}

浮點數數據類型
浮點數包括float(4字節),double(8字節),long double(用于高精度計算中,一般用不到)

浮點數常量又多種表示方法,要么包含小數點,要么包含字母E(e)
浮點數常量默認是double,如果需要表示float ,在浮點數常量后買你添加字母F(f)

57.0
57.
5.70e1( 表示以10為底的數,表示5.70*10^1)
.57e2

讀寫浮點數

%f : float
%lf : double(注意l不能大寫)
double i;
scanf("%lf",&i);
printf("%lf",&i);

字符數據類型
char類型大小為1個字節,并且使用ASCII編碼表示,ASCII編碼用7位表示128個字符(最高位都為0)
在這里插入圖片描述
C語言把字符類型當作小的整數類型來使用,因此可以對字符執行算術運算和比較運算

int i = 'a';
char ch = 'A';
ch = ch + 1;
//將大寫轉換位小寫
if(ch >= 'A' || ch <= 'Z') {ch = ch + 'a' - 'A';
}

不能直接輸入的字符----轉義字符
字符轉義序列:

\a 警報,響鈴
\b 回退
\f 換頁
\n 換行
\r 回車
\t 水平制表符
\v 垂直制表符
\\ backslash
\? question mark
\' single quote
\" single quote

數字轉義序列
八進制形式表示:以\開頭,后面接最多3個八進制數 \o, \101 ‘A’
十六進制表示形式:以\x開頭,后面接十六進制數字 \x0,\x41 ‘A’

printf("%c",'\101');//輸出A
printf("%c",'\x41');//輸出A

字符處理函數
character classification分類函數
需要導入頭文件ctype.h
characet manipulation操作函數
在這里插入圖片描述

讀寫字符
scanf/printf配合%c來讀寫字符
注意事項:%c不會忽略前面的空格字符,可以在%c前面添加一個空格來實現忽略前面的空格,這樣的操作還可以忽略換行

scanf(" %c",&ch);

getchar(把字符寫到stdin中)/putchar(把字符寫到stdout中),效率比scanf/printf效率要高

ch = getchar();//讀入字符到stdin
putchar(ch);//將字符傳到stdout

布爾類型
c99中定義了布爾類型,在<stdbool.h>頭文件中

#include <stdbool.h>

bool 類型本質上是無符號整數類型
注意:給布爾類型變量復制,非零會得true,零會得到false

類型轉換
1.為什么需要進行類型轉換
計算機硬件只能對相同類型的數據運算,計算機是沒有數據類型的概念的
2.何時會發生類型轉換
給定多的數據類型與需要的數據類型不匹配時
3.如何進行類型轉換
隱式類型轉換(編譯器做的類型轉換,不需要程序員手動指明)

short ,char只要參與運算就會轉換位int類型進行運算(整數提升)
intlong類型進行運算int類型會轉換為long類型進行運算,
long類型和longlong類型運算long類型會轉換位longlong類型,
longlong類型和float類型運算,longlong類型會轉換為float類型
float類型和double類型運算,float類型會轉換位double類型
注意:不要將有符號整數和無符號整數進行運算,因為他們會進行類型轉換,就會使用補碼進行運算,運算的結果可能就會出錯

顯示轉換(強制類型轉換):可以讓程序員更精確的控制類型轉換

//強制類型轉換的好處
//1.使用顯示轉換實現計算浮點數的小數部分
double d = 3.14,f;
f = d - (int)d;
//2.增強代碼的可讀性,表明肯定會發生的轉換
float = f = 3.14;
//...
int i = (int)f;
//3.對類型轉換進行更精確的控制
int divided = 4,divisor = 3;
double = quo;
//quo = divided / divisor;//1.0
quo = (double)divided / divisor//1.3333333....//4.避免溢出
long long millisPerday = 24*60*60*1000;//每天的秒
long long nanosPerday = (long long)24*60*60*1000*1000*1000;//每天的毫秒,在前面加上強制類型轉換就不會出錯
printf("%lld\n",nanosPerday/millisPerday);//沒有加(long long)強制類型轉換時輸出-21,因為24,60,1000這些數據都是int類型的數據,雖然我們最終的結果沒有超過longlong類型的長度,但是超過了int類型的長度,int類型進行運算會先將結果存儲在int類型的長度變量里,再將其轉換為longlong類型,因此變換之前就超過int類型的長度就會出先計算錯誤

Typedef
我們可以使用typedef給類型起別名
格式

typedef type_name alias;
typedef int Bool;//Bool為int數據類型的別名

(1)typedef和宏定義的區別
宏定義是在預處理階段進行處理的(簡單的文本替換),編譯器是不能夠識別宏定義的,因此如果宏定義中有錯誤編譯器就不能給出一些友好提示;編譯器能夠識別typedef定義的別名,如果發生錯誤,就能給出一些友好提示信息
定義類型:使用typedef不要使用宏定義
(2)給類型起別名的好處
a.增加代碼的可讀性
b.增加代碼的可移植性

sizeof運算符
在編譯階段就進行計算的,因此他是一個常量表達式,可以表示數組的長度
作用:計算某一類型的數據所占內存空間的大小(以字節為單位)

int i = 3;
//語法
sizeof(type_name);
int arr[sizeof(i)];//正確表示

運算符以及優先級
注意事項:
(1)+、-、*、/可以用于浮點數,但是%必須要求兩個操作數都是整數
(2) 兩個整數相除,其結果為整數
(3)a%b的結果可能為負,符號與a的符號相同,滿足a%b = a - (a/b)*b
在這里插入圖片描述

在這里插入圖片描述

//取模
bool is_odd(int n) {return n%2 ==1;//錯誤的,如果n = -1,那么會返回true
}
bool is_odd_1(innt n) {return n%2 != 0;
}
//更高效算法
bool is_odd_2(int n) {return n & 0x1;//讓n和1進行按位與,最后是結果是1那么就是奇數,結果為0那么就是偶數
}

位運算符

<<、>>、&、|、^、~
移位運算符
i<<j:就左移j位,在左邊補0
i>>j:將i右移j位,若i為為無符號整數或者非負數,則左邊補0,若i為負數,他的行為是由實現定義的,有的左邊會補0,有的左邊補1
為了代碼的可移植,最好不要對有符號整數進行移位運算

//s左移兩位
short s = 13;
printf("s << 2 = %d\n",s<<2);//52
//左移兩位0000 0000 0000 1101   --->  0000 0000 0011 0100
//若沒有發生溢出,左移J位,相當于乘以2^J//s右移兩位
short s1 = 13;
printf("s1 >> 2 = %d\n",s>>2);//3
// 0000 0000 0000 1101   --->   0000 0000 0000 0011
//右移j位,相當于除于2^j(向下取整)

按位運算符


short i = 3,j = 4;
//按位取反
~i(取反):0000 0000 0000 0011  ---> 1111 1111 1111 1100 (-4)
i&j(按位與):0000 0000 0000 0011 & 0000 0000 0000 0100  --->   0000 0000 0000 0000 (0)
i|j(按位或):0000 0000 0000 0011 | 0000 0000 0000 0100  --->   0000 0000 0000 0111 (7)
i^j(異或):0000 0000 0000 0011 ^ 0000 0000 0000 0100  --->   0000 0000 0000 0111 (7)
//異或性質:
a ^ 0 = a
a ^ a = 0
a ^ b =  b ^ a (交換律)
a^(b^c) = (a^b)^c (結合律) 
//1.如何判斷一個整數是否為2的冪
//方法1
bool isPowerO2(unsigned int n) {unsigned int i = 1;while(i < n) {i <<=1;	}return i == n;
}
//方法2
bool is PowerOf2(unsigned int n) {return (n & n-1) == 0;
}
//2.的冪的二進制表示有神什么特征:只有一個1
// 0000 0000 0100 0000 & 0000 0000 0011 1111   --->  0000 0000 0000 0000 (0)//2.給定一個不為零的整數,找出值為一且權重最低的位
//輸入:0011 0100   輸出::4
((n ^ n-1) + 1) >> 1
n & (-n)  : 0011 0100 (n) & 1100 1100 (-n) ---> 0000 0100 (4)//3. 給定一個整數數組,里面的數都是成對的,只有一個數例外,請找出這個數
int arr[] = {1,2,3,4,5,4,3,2,1};
printf("%d\n",findSingleNumber(arr,9));int findSingleNumber(int arr[],int a) {int singleNum = 0;for(int i = 0;i < n;i++) {singleNum ^= arr[i];}return singleNum;
}

數組
為什么在大多數語言中,數組的索引都是從0開始的?
原因是方便尋址
若索引從0開始:i_addr = base_addr + i*sizeof(element_type)
若索引從1開始:i_addr = base_addr + (i-1)*sizeof(element_type);每次尋址多執行一次減法運算
為什么數組的效率一般會優于鏈表?
(1)數組的內存空間是連續的,而鏈表的內存空間不連續,數組可以更好的利用CPU的cache(預讀,局部性原理)
(2)數組只需要存儲數據,鏈表不僅經要存儲數據,還需要存儲指針域,數組的內存使用率更高

數組的聲明:int arr[size]
注意事項:size必須是整形的常量表達式,在編譯期間能計算出數組的大小
數組的初始化:

#define SIZE(a) (sizeof(a)/sizeof(a[0]))//計算數組長度
int arr[10] = {0,1,2,3,4,5,6,7,8,9};
int arr[10] = {1,2,3};//其余?初始化為0,{1,2,3,0,0,0,0,0,0,0}
int aar[10] = {0};//將數組所有元素初始化為0
int arr[] = {1,2,3,4,5,6,7,8,9,10};//數組長度編譯器自行推斷,這里的長度是10

二維數組的初始化:
二維數組是以行優先的形式進行初始化的

int matrix[3][4] = {{1,2,3,4},{2,2,3,4},{3,2,3,4}};//
int matrix[3][4] = {1,2,3,4,2,2,3,4,3,2,3,4};//不建議
int matrix[3][4] = {0};
int matrix[][4] = {{1,2,3,4},{2,2,3,4},{3,2,3,4}};//編譯器自行判斷行的大小
//注意事項:不能省略列的大小

常量數組:

const int arr[10] = {0,1,2,3,4,5,6,7,8,9};//數組元素不能發生改變,存放靜態數據

生成隨機數:

srand((unsigned)time(NULL));//利用時間設置隨機數種子
for(int i = 0;i < 10;i++) {printf("%d\n",rand());//rand默認隨機數種子為1
}

一維數組作為參數傳遞的時候會退化為指向第一個元素的指針,好處
(1)可以避免數據復制,
(2)可以修改原始數組的值,
(3)函數調用會更加靈活
數組作為參數傳遞的時候會丟失類型信息,數組長度

//傳遞數組的時候將數組長度一并傳遞
int sum_arr(int arr[],int length);

二維數組在作為參數傳遞的時候不能省略列的信息,只能省略行的信息

int main() {int materix[3][4] = {{1,2,3,4},{2,2,3,4},{3,2,3,4}};printf("%d\n",sum_arr(materix,3));return 0;
}
int sum_arr(int materix[][4],int n){int sum = 0;for(int i = 0;i < n;i++) {for(int j = 0;j < 4;j++) {sum += materix[i][j];}}return sum;
}

如果我們要在main函數里面退出程序可以使用return語句,當我們不在 main函數里面但是想退出程序我們可以使用exit函數exit(EXIT-SUCCESS) 或者exit(0)—正常退出,exit(EXIT-FAILUE)或exit(1)—異常退出,

#define EXIT-SUCCESS 0
#define EXIT-FAILUE 1

指針

計算機最小的尋址單位:字節
變量的地址:變量第一個字節的地址
指針建檔的來說,指針就是地址
指針變量:存放地址的變量,有時候把指針變量稱為指針

聲明指針時,需要指明基礎類型

int *p;//p為變量名;變量的類型是int *,而不是int 

兩個基本操作:取地址運算符&和解引用*
取地址運算符:int i = 1; int *p = &i;取出變量i的地址賦值給int *
解引用運算符:通過解引用運算符訪問指針指向的對象 printf("%d\n",*p);//1
p相當于i的別名,修改p相當于修改i
i直接訪問(訪問一次內存)
*p間接訪問(訪問兩次內存)

野指針
未初始化的指針或者是指向位置區域的指針
野指針會造成位置錯誤

//野指針
int *p;
int *q = 0x7f;

指針和數組

指針的算術運算
(1)指針加上一個整數
(2)指針減去一個整數
(3)兩個指針相減(指向同一個數組里面的元素)
指針的算術運算是以元素的大小為單位的,而不是以字節為單位

int arr[10] = {0,1,2,3,4,5,6,7,8,9};
int* p = &arr[2];
int* q = p+3;
p += 6;
printf("*p = %d,*q = %d\n",*p,*q);//8,5
------------------------------------------------------------------------------//指針的比較(兩個指針指向同一個數組的元素)
// p - q > 0 <=> p > q
// p - q = 0 <=> p = q
// p - q < 0 <=> p < q
int* p = &arr[2];
int* q = &arr[5];
printf("p - q = %d\n",p - q);//-3
printf("q - p = %d\n",q - p);//3
------------------------------------------------------------------------------//用指針處理數組
int sum = 0;
for(int* p = &arr[0]; p < &arr[10];p++){//&arr[10]只會計算arr[10]的地址,不會訪問arr[10],因此不會發生數組越界sum += *p;
}
printf("sum = %d\n",sum);//45
------------------------------------------------------------------------------int sum = 0;
int* p = &arr[0];
while(p < &arr[10]) {sum += *p++;
}
printf("sum = %d\n",sum);

*和++的組合
*p++,*(p++)表達式的值為*p,p自增
(*p)++表達式的值為*p,*p自增
*++p,*(++p)表達式的值為*(p+1),p自增
++*p,++(*p)表達式的值為*p+1,*p自增
*和–的組合和上面類似

數組名作可以作為指向索引為0的元素的指針

int arr[10] = {0,1,2,3,4,5,6,7,8,9};
*arr = 100;
*(arr +7) = 700;
//arr[10] = {100,1,2,3,4,5,700,7,8,9}
int sum = 0;
for(int*p = arr;p < arr+9;p++) {sum += *p;
}
sum = 0;
for(int i = 0;i < 10;i++) {sum += (arr+i);
}

指針也可以作為數組名來使用(可以對指針使用[]運算符) p[i] == *(p+i)

總結:指針和數組之間的關系:
(1)可以利用指針處理數組(指針的算術運算)
(2)數組名可以做指向該數組索引為0元素的指針
(3)指針也可以作為數組名(可以對指針使用[]運算符,p[i] == *(p+i)

字符串

C語言是通過字符數組存儲字符串字面量的
字符串的初始化
在這里插入圖片描述

在這里插入圖片描述
在這里插入圖片描述

讀寫字符串

寫:printf + %s, puts---string

char name[] = "Allen";
printf("%s\n",name);
puts(name);//寫完字符串后,會在后面添加額外的換行符  puts(name)等價于printf("%s\n",name)

讀:scanf + %s,gets,gets_s

#define N = 100
char name[N];
scanf("%s",name);//讀取規則:會跳過前面的空白字符,讀取字符存入到數組中,知道遇到空白字符位置,然后會在后面添加空字符’\0‘
//注意事項
//(1)永遠不會包含空白字符
//(2)sacnf不會檢查數組越界
gets(name);//不會跳過前面的空白字符,讀取字符存入到數組中,知道遇到換行符為止,然后再后面添加’\0‘
//注意事項:
//同樣gets也不會檢查數組越界
gets_s(name,n);//n表示數組的長度,所以最多能夠讀n-1個字符,第n個位空字符’\0‘,會檢測數組越界,遇到換行符渡或者檢測到數組越界就停止讀入

字符串的庫函數
(1)size_t strlen(const char* s)獲取字符串的長度,不包含空字符’\0‘,使用const常量指明再strlen中不會修改s指向的內容,傳入參數

printf("%d\n",strlen("abc"));//3
printf("%d\n",strlen(""));//0

(2)int strcmp(const char* s1,const char* s2)比較字符串,按照字典順序比較s1和s2,“abc” > "acb","abc" >"abd","abc" < "abcd",
如果s1 > s2,則返回正數
如果s1 = s2,則返回零
如果s1 < s2,則返回負數

(3)char* strcpy(char* s1,const char* s2)【不安全的,因為不會檢查數組越界】把s2指向的字符串復制到s1指向的數組中,不會檢查數組越界,s1變量沒有攜帶const關鍵字,表明通常會在函數中修改s1指向的內容,傳入傳出參數
char* strncpy(char* *dest,const char* src,size_t count)【安全的】指定目標數組中可以接收的大小

char s1[10];
strncpy(s1,"Hello",4);//s1 ==> Hell不會寫入空字符'\0'
strncpy(s1,"Hello",6);//s1 ==>Hello \0
strncpy(s1,"Hello",8);//s1 ==>Hello \0 \0 \0 \0 后面會添加額外的空字符,直到寫入8個字符

(4)char* strcat(char* dest,const char* src)將字符串src的內容追加到字符串dest的末尾,并返回dest(不會檢查數組越界)

(5)char* strncat(char* dest,const char* src,size_t coant)會在dest末尾添加src中的coant個字符,因為strncat總是會寫入‘\0’因此我們一般會這樣調用strncat(s1,s2,sizeof(s1)-strlen(s1)-1),給空字符預留一個空間

char s1[10] = "Hello";
strcat(s1," world");//s1 ===>Hello' 'world \0
strncat(s1," world",2);//s1 ===>Hello' 'world \0
strncat(s1," world",7);//s1 ===>Hello' 'world \0

字符串慣用法
自己編寫strlen函數

size_t my_strlen(const char* s) {size_t n;for(int n = 0; *s != '\0';s++) {n++;}return n;
}
//改進后
size_t my_strlen(const char* s) {char *p = s;while(*p++);return p-s-1;//s指向了空字符后面的字符
}
size_t my_strlen(const char* s) {char *p = s;while(*p){p++;}return p-s;
}

自己編寫strcat函數

char* my_strcat(char* s1,const char* s2) {char* p = s1;while(*p) {p++;}while(*s2 != '\0') {*p = *s2;p++;s2++;}*p = '\0';return s1;
}
//改進后
char* my_strcat(char* s1,const char* s2) {char* p = s1;while(*p) {p++;}while(*p++ = *s2++);return s1;
}

字符串數組

char* planets[] = {"Mecury","Venus","Earth,"Mars","Jupitor","Saturn","Uranus","Neptune","Pluto"};

結構體

c語言的結構體相當于其他高級語言中的類,c語言只能在結構體中定義數據

//定義結構體
struct students{int id;char name[25];bool gender;int chinese;
}
int main() {//1.初始化結構體struct students t1 = {1,"liuyifei",false,100};struct students t2 = {2,"huasheng",true};//未被初始化的成員都會被賦值未0//2.對結構體的操作printf("name = %s\n",t1.name);
}
//為了避免拷貝數據,我們往往會傳遞一個指向結構體的指針
void printf_student(struct student_s* s){printf("%d %s %d %d\n",(*s).id,(*s).name,(*s).gender,(*s).chinese)
}
//C語言程序一般時通過指針去引用結構體的,C語言提供了一個特別的運算符->
void printf_student(struct student_s* s){printf("%d %s %d %d\n",s->id,s->name,s->gender,s->chinese)
}
//3.使用typede為結構體起別名
typedef struct students{int id;char name[25];bool gender;int chinese;
} student_s;//別名student_s

注意事項:當結構體作為參數或者返回值時,會拷貝整個結構體中的數據

指針的高級應用

(1)動態內存分配
在頭文件<stdlib.h>定義了三個動態內存分配的函數(在堆上分配內存空間)

  1. void* malloc(size_t size);分配size個字節的內存,不會對分配的內存塊清零;若分配不成功,返回空指針
  2. void* calloc(size_t num,size_t size);num個元素分配內存空間,每個元素的大小為size個字節,并對內存塊清零;若分配不成功,返回空指針
  3. void* realloc(void* ptr,size_t size);調整先前分配內存塊的大小,如果分配成功,返回指向新內存
    注意事項:ptr應該指向先前使用動態內存分配函數分配的內存塊

空指針:不指向任何對象的指針(用宏NULL表示,其值為0)

#include <stdio.h>
#include <stdlib.h>int main(void) {char* s1 = "Hello ";char* s2 = "world! ";char* s = my_strcat(s1,s2);puts(s1); //Hello puts(s2); //world!puts(s);//Hello world!return 0;}char* my_strcat(const char* s1,const char* s2){char* s = (char *)malloc(strlen(s1) + strlen(s2) + 1);if(s == NULL) {//未分配成功//做錯誤處理return NULL;}strcpy(s,s1);//將s1賦值到s中strcat(s,s2);//將s2復制到s末尾return s;}//以上代碼沒有釋放內存空間

如果申請的內存空間沒有釋放,就可能造成內存泄漏現象
分配的內存沒有指針指向它,導致不能訪問的內存被稱為垃圾
如果程序中存在垃圾,這種現象稱為內存泄漏
如何避免內存泄漏?
使用void free(void* ptr);進行內存釋放,ptr必須是之前申請的內存空間的指針

(2)指向指針的指針(二級指針)

#include <stdio.h>
#include <stdlib.h>
typedef struct node_s{int val;struct node_s* next; 
} Node;
void add_to_list(Node** ptr_list,int val);
int main(){Node* list = NULL:add_to_list(&list,1);add_to_list(&list,2);add_to_list(&list,3);add_to_list(&list,4);return 0;
}
void add_to_list(Node** ptr_list,int val){Node* newNode = (Node*)malloc(sizeof(Node));if(newNode === NULL) {printf("Error:malloc failed in add_to_list.\n");exit(1);}//頭插法newNode->val = val;newNode->next = *ptr_list;*ptr_list = newNode;
}

(3)指向函數的指針(函數指針)

#include <stdio.h>
#include <math.h>
#define PI 3.1415926
double average(double (*f)(double),double a,double b);
int main(void){double avg = average(sin,0,PI);printf("%lf",avg);return 0;
}
double average(double (*f)(double),double a,double b){return (*f)((a+b)/2);
}
//簡便寫法
//double average(double f(double),double a,double b){
//	return f((a+b)/2);
//}

qsort
void qsort(void *ptr,size_t count,size_t sizre,int (*comp)(const void *,const void *))
ptr---->指向要排序的數組
count---->數組中元素的個數
size---->元素的大小
comp---->比較函數,如果第一個參數大于第二個參數返回值正值,如果第一個參數等于第二個參數返回零,如果第一個參數小于第二個參數,返回負值
可以對任何類型的數組進行排序,不管元素類型是什么

#include <stdio.h>
#include <string.h>
typedef struct student_s{int number;char name[25];int chinese; int math;int english;
} Studet;
int compare(const void* p1,const void* p2);#define SIZE(a) (sizeof(a)/sizeof(a[]0]))
int main(void) {Student students[5] = {{1,"liuyifei",100,100,100},{2,"wangyuyan",99,100,100},{3,"zhaolinger",100,99,100},{4,"xiaolongnv",100,100,99},{5,"baixiuzhu",100,100,99}};qsort(students,SIZE(students),sizeof(Student),compare);return 0;
}
//比較規則:總分從高到低,語文成績(高-->低)數學成績(高-->低),英語成績(高-->低),姓名(字典順序從小到大進行比較)
int compare(const void* p1,const void* p2) {Student* s1 = (Student*)p1;Student* s2 = (Student*)p2;int total1 = s1->chinese + s1->english + s1->math;int total2 = s2->chinese + s2->english + s2->math;if(total1 != total2) {return total2 - total1;}if(s1->chinese != s2->chinese){return s2->chinese - s1->chinese;}if(s1->math != s2->math){return s2->math - s1->math;}if(s1->english != s2->english){return s2->english - s1->english;}return strcmp(s1->name,s2->name);
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/209977.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/209977.shtml
英文地址,請注明出處:http://en.pswp.cn/news/209977.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【USB、串口、COM口、TTL、RS-232、RS-485區別詳解】

USB&#xff0c;串口&#xff0c;COM口&#xff0c;TTL&#xff0c;RS-232&#xff0c;RS-485區別詳解 1. USB&#xff0c;串口&#xff0c;COM口&#xff0c;TTL&#xff0c;RS-232&#xff0c;RS-485區別詳解2 USB轉TTL2 RS-232轉TTL3 USB4 UART5 STM32串口異步通訊需要定義的…

iOS——定位與地圖

平時在寫項目的時候可能會遇到需要使用定位服務的地方&#xff0c;比如說獲取位置和導航等。因此這里我會使用OC自帶的庫以及蘋果系統的地圖來獲取定位以及顯示在地圖上。 開始前的設置 在獲取定位前&#xff0c;需要在項目文件的info中添加兩個關鍵字&#xff0c;用于向用戶…

從零開始的C++(二十一)

C11 1.列表初始化&#xff1a; //允許以下代碼正確運行int a[]{1,2,3};//效果與int a[]{1,2,3}一致 即允許省略等于號。同時&#xff0c;允許用花括號對所有自定義類型和內置類型進行初始化&#xff0c;而非以前花括號只能對數組進行初始化。利用花括號對自定義類型初始化時…

LeetCode刷題--- 求根節點到葉節點數字之和

個人主頁&#xff1a;元清加油_【C】,【C語言】,【數據結構與算法】-CSDN博客 個人專欄&#xff1a;http://t.csdnimg.cn/ZxuNL http://t.csdnimg.cn/c9twt 前言&#xff1a;這個專欄主要講述遞歸遞歸、搜索與回溯算法&#xff0c;所以下面題目主要也是這些算法做的 我講述…

【ITK庫學習】使用itk庫進行圖像濾波ImageFilter:鄰域濾波

目錄 1、itkMeanImageFilter 均值濾波器2、itkMedianImageFilter 中值濾波器3、itkBinaryMedianImageFilter 二值中值濾波器4、擴展itkNeighborhood5、擴展itkNeighborhoodIterator6、擴展itkNeighborhoodOperator 領域濾波是一種信號處理方法&#xff0c;用于去除信號中的噪聲…

★560. 和為 K 的子數組(自己做出來了)

560. 和為 K 的子數組 前綴和的知識。 如果要求i~j下標之間的元素和&#xff0c;用前綴和的話&#xff0c;應該是b[j] - b[i-1]&#xff0c;i處的值也應該包括。 所以這個題&#xff0c;前綴和數組就要比原數組整體向后平移一個單元格&#xff0c;不然在求0~n的和的時候沒法取…

在python中安裝庫,會有conda安裝,也會有pip安裝,conda與pip的區別是什么?

文章目錄 一、Conda是什么&#xff1f;二、pip是什么&#xff1f;三、pip與conda的區別&#xff1a;總結 一、Conda是什么&#xff1f; Conda是一個開源的包管理系統&#xff0c;它是Anaconda公司為Python和其他編程語言開發的。它主要用于數據科學和機器學習領域&#xff0c;…

【Vue】日常錯誤總結(持續更新)

日常遇到的小問題匯總, 內容小篇幅少的就全放這里了, 內容多的會在Vue專欄單獨分享~ 目錄 【Q】 el-form-item值為 null 或 undefined顯示““ 【Q】dialog內組件數據刷新總是延遲慢一拍 問題背景描述 解決方案 代碼簡單模擬 JS 【Q】el-input 不能輸入的解決辦法 方法…

Educational Codeforces Round 156 (Rated for Div. 2)補題

Sum of Three 題目大意&#xff1a;將一個正整數n分成3個不同的正整數x,y,z,保證三個數都不能整除3&#xff0c;如果無法實現就輸出NO. 思路&#xff1a;這個題實際上特別簡單&#xff0c;我們可以發現當n比較大的時候&#xff0c;我們可以從中取1&#xff0c;然后第二個數也…

【Java】Java環境以及EditPlus編輯器安裝與配置流程

要安裝和配置Java環境以及EditPlus編輯器&#xff0c;請按照以下步驟操作&#xff1a; ### 安裝Java Development Kit (JDK) 1. 訪問Java官方網站下載最新版本的JDK。 2. 運行下載的JDK安裝程序&#xff0c;并按照提示完成安裝。 3. 安裝完成后&#xff0c;記下JDK的安裝路徑&a…

perf與火焰圖-性能分析工具

參考鏈接 perf性能分析工具使用分享 如何讀懂火焰圖&#xff1f;-阮一峰 perf基本用法-record,report-知乎 火焰圖抓取 準備&#xff1a; centos安裝perf工具 dnf install perf下載火焰圖解析代碼 git clone https://github.com/brendangregg/FlameGraph.git抓取指定進程…

Orcal數據庫Schema理解、表分區理解

目錄 1 Schema1.1 Orcal數據庫示例1.2 MySQL數據庫示例 2 Orcal表分區2.1 創建表分區2.2 查看表分區2.3 查看指定分區數據 此前未了解過Schema的概念&#xff0c;僅知道Orcal數據庫比較側重這個概念&#xff0c;搜遍全網都&#xff0c;都是啰哩吧嗦的搬抄定義&#xff0c;特此在…

LeetCode算法題解(單調棧)|LeetCode503. 下一個更大元素 II、LeetCode42. 接雨水

一、LeetCode503. 下一個更大元素 II 題目鏈接&#xff1a;503. 下一個更大元素 II 題目描述&#xff1a; 給定一個循環數組 nums &#xff08; nums[nums.length - 1] 的下一個元素是 nums[0] &#xff09;&#xff0c;返回 nums 中每個元素的 下一個更大元素 。 數字 x 的…

LIMoE:使用MoE學習多個模態

文章鏈接&#xff1a;Multimodal Contrastive Learning with LIMoE: the Language-Image Mixture of Experts 發表期刊&#xff08;會議&#xff09;: NeurIPS 2022 目錄 1.背景介紹稀疏模型 2.內容摘要Sparse Mixture-of-Experts ModelsContrastive LearningExperiment Analy…

Kubernetes入門筆記 ——(3)理解pod對象

為什么需要pod 最為熟知的一句話&#xff1a;pod是k8s的最小調度單位。剛開始聽到這句話時會想&#xff0c;已經有容器了&#xff0c;k8s為什么還要搞個pod出來&#xff1f;容器和pod是什么關系&#xff1f;容器的本質是進程&#xff0c;而k8s本質上類似操作系統。 熟悉Linux的…

SpringBoot系列之啟動成功后執行業務的方法歸納

SpringBoot系列之啟動成功后執行業務邏輯。在Springboot項目中經常會遇到需要在項目啟動成功后&#xff0c;加一些業務邏輯的&#xff0c;比如緩存的預處理&#xff0c;配置參數的加載等等場景&#xff0c;下面給出一些常有的方法 實驗環境 JDK 1.8SpringBoot 2.2.1Maven 3.2…

python dataframe 列中 字符串( ‘2815512706605‘)過大 轉不了float 用Decimal

from decimal import Decimaldf["accFillSz"] df["accFillSz"].apply(lambda x: Decimal(x)) 2815512706605這個值超出了Python中float類型的最大表示范圍,無法直接轉換為浮點數。 Python中float類型使用IEEE 754標準的64位雙精度浮點數表示,最大值大約為…

歐拉回路歐拉路【詳解】

1.引入 2.概念 3.解決方法 4.例題 5.回顧 1.引入 經典的七橋問題 哥尼斯堡是位于普累格河上的一座城市&#xff0c;它包含兩個島嶼及連接它們的七座橋&#xff0c;如下圖所示。 可否走過這樣的七座橋&#xff0c;而且每橋只走過一次&#xff1f; 你怎樣證明&#xff1f;…

【Linux top命令】

文章目錄 深入了解Linux top命令&#xff1a;實時監控系統性能1. 什么是top命令&#xff1f;2. 使用top命令3. top命令交互操作 深入了解Linux top命令&#xff1a;實時監控系統性能 1. 什么是top命令&#xff1f; top命令是一個用于實時監控系統性能的文本界面工具。它顯示當…

Linux上使用獨立顯卡Tesla T4(測試視頻壓縮)

背景 將視頻處理程序單獨部署至K8S之外&#xff0c;使用獨立GPU顯卡的一臺服務器上。 需事先對GPU性能做簡單測試。 已通過zabbix對Linux進行了系統資源監控。 已通過PrometheusGrafana對顯卡Tesla T4做了性能監控。 逐步補充&#xff0c;稍等 2023年12月6日 操作 查看當前…