學生時代所學的一些 C 語言知識點回顧(1)
- 2019 年 10 月 4 日
- 筆記
版權聲明:本文為博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
本文鏈接:https://blog.csdn.net/solaraceboy/article/details/100668093
文章目錄
學生時代所學的一些 C 語言知識點回顧(1)
0. 前言
時間過得真快,一眨眼之間已經畢業很多年,C 語言是大學裏所學的第一門編程語言。由於很長時間不用,很多知識點都已生疏,最近抽了個空對之前的一些知識點做了一些回顧,謹以此系列文章記錄一下這些剛剛回顧過的知識點。
1.整型與浮點型兩種數據類型相乘
#include<stdio.h> int main() { int a = 20; float b = 20.34; printf("%fn",a*b); return 0; } //406.799988
#include<stdio.h> int main() { int a = 20; float b = 20.34; printf("%dn",a*b); return 0; } //-1409143032
#include<stdio.h> int main() { int a = 20; float b = 20.34; printf("%dn",(int)(a*b)); return 0; } //406
如果不進行強制類型轉換,那麼整型無法保存浮點型的數據。
2.命令行傳參
#include<stdio.h> #include<stdlib.h> #include<string.h> int main(int argc, char *argv[]) { int memory_num = 0; int i; char *cmd,*temp; for (i = 0; i < argc; i++) memory_num += strlen(argv[i]); cmd = (char *)malloc(memory_num + argc*strlen(" ")); for (i = 1; i < argc; i++) { //printf("argv:%sn",argv[i]); temp = (char *)malloc(strlen(argv[i])+strlen(" ")); strcpy(temp,argv[i]); strcat(temp," "); //printf("argc[%d]:%s|n",i,temp); strcat(cmd,temp); free(temp); } printf("%sn",cmd); system(cmd); return 0; } /* $ ./cmd ls /;tree ~/docker-build/tesseract-ocr/ ls / bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var /home/gysl/docker-build/tesseract-ocr/ ├── 124.jpg ├── 124.txt ├── 1.png ├── 2.jpg ├── 3.jpg ├── 4.png ├── 4.txt ├── build │ ├── 4.1.0.tar.gz │ ├── Dockerfile │ ├── leptonica-1.78.0.tar.gz │ └── tesseract_langs.tar.gz ├── gysl.jpg.txt ├── gysl.txt └── langs ├── chi_sim.traineddata ├── chi_sim_vert.traineddata └── eng.traineddata 2 directories, 16 files */
這一段代碼演示 main() 函數傳參的具體情形,稍加改造即可以用於一些安全性較高的 shell 腳本的加密。
3. 運算符優先級
#include<stdio.h> int main(int argc,char *argv[]) { int a = 5, b, c; c = (b = a + 2) - (a=1); printf("%dt%dn",c,a); return 0; } // 6 1
4. for 語句裏面的逗號運算符
#include<stdio.h> int main(int argc,char *argv[]) { int a = 15, b = 26, i, j; for ( ; i < a, j < b;i++, j++) {} printf("%dt%dn",i,j); return 0; } // 26 26
#include<stdio.h> int main(int argc,char *argv[]) { int a = 15, b = 26, i, j; for ( ; i < a, j < b;i++, j++) ;//{} printf("%dt%dn",i,j); return 0; } // 26 26
#include<stdio.h> int main(int argc,char *argv[]) { int a = 15, b = 26, i, j; for ( ; i < a, j < b;i++, j++) //{} printf("%dt%dn",i,j); return 0; } /* 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15 16 16 17 17 18 18 19 19 20 20 21 21 22 22 23 23 24 24 25 25 */
#include<stdio.h> int main(int argc,char *argv[]) { int a = 15, b = 6, i, j; for ( ; i < a, j < b;i++, j++) {} printf("%dt%dn",i,j); return 0; } // 6 6
#include<stdio.h> int main(int argc,char *argv[]) { int a = 5, b = 6, i, j; for ( ; i < a, j < b;i++, j++) //{} printf("%dt%dn",i,j); return 0; } /* 0 0 1 1 2 2 3 3 4 4 5 5 */
這種情況以後一個變量的值為上限。for 語句在循環結束之後循環體最後一部分仍會繼續執行一次。
5. 各數據類型的長度
#include<stdio.h> int main(int argc,char *argv[]) { printf("int:%dnlong int:%dnshort int:%dnunsigned int:%dnunsigned long int:%dnunsigned short int:%dn",sizeof(int),sizeof(long int),sizeof(short int),sizeof(unsigned int),sizeof(unsigned long int),sizeof(unsigned short int)); return 0; } /* int:4 long int:8 short int:2 unsigned int:4 unsigned long int:8 unsigned short int:2 */
6. 結構體
#include <stdio.h> struct stu{ char *name; //姓名 int num; //學號 int age; //年齡 char group; //所在小組 float score; //成績 }stus[] = { {"Zhou ping", 5, 18, 'C', 145.0}, {"Zhang ping", 4, 19, 'A', 130.5}, {"Liu fang", 1, 18, 'A', 148.5}, {"Cheng ling", 2, 17, 'F', 139.0}, {"Wang ming", 3, 17, 'B', 144.5} }, *ps; int main(){ //求數組長度 int len = sizeof(stus) / sizeof(struct stu); printf("NamettNumtAgetGrouptScoretn"); for(ps=stus; ps<stus+len; ps++){ printf("%st%dt%dt%ct%.1fn", ps->name, ps->num, ps->age, ps->group, ps->score); } return 0; }
7. 一些值得思考的問題
# include<stdio.h> # include<string.h> int main(int argc,char *argv[]) { char e[4] = "20d0"; int i; printf("Sizeof: %dt%dn",(sizeof e),strlen(e)); printf("Sizeof int: %dn",sizeof (int)); printf("Sizeof e: %dn",sizeof (e)); /* for ( i = 0; i < strlen(e); i++) printf("e[%d]: %cn",i,e[i]); */ printf("%lun",((unsigned long)sizeof(int))); return 0; }
以上代碼注釋部分去掉之後,第一個printf輸出的值會出現不一樣。
8. 數組的初始化
# include<stdio.h> int main(int argc, char *argv[]){ int a[10] = {1,2,4,5,[0] = 0,6,8,9,3}; int i = 0; for ( i = 0; i < 10; i++) printf("a[%d]: %dn",i, a[i]); return 0; } /* a[0]: 0 a[1]: 6 a[2]: 8 a[3]: 9 a[4]: 3 a[5]: 0 a[6]: 0 a[7]: 0 a[8]: 0 a[9]: 0 */
# include<stdio.h> int main(int argc, char *argv[]){ int a[10] = {1,2,4,5,[3] = 0,6,8,9,3}; int i = 0; for ( i = 0; i < 10; i++) printf("a[%d]: %dn",i, a[i]); return 0; } /* a[0]: 1 a[1]: 2 a[2]: 4 a[3]: 0 a[4]: 6 a[5]: 8 a[6]: 9 a[7]: 3 a[8]: 0 a[9]: 0 */
這樣的申明是不合法的。編譯器在處理初始化列表是,會記錄下一個待初始化的數組元素的位置。正常情況下,下一個元素是剛被初始化的元素後面的那個。但是,當列表種出現初始化式時,下一個元素會被強製為指示符對應的元素,即使該元素已經初始化了。
9. 變長數組的初始化
# include<stdio.h> int main(int argc, char *argv[]){ int n, i, a[n]; scanf("%d",&n); for ( i = 0; i < n; i++){ scanf("%d",&a[i]); } for ( i = 0; i < n; i++){ printf("a[%d]: %dn",i,a[i]); } return 0; } /* 3 5 8 1 a[0]: 5 a[1]: 8 a[2]: 1 */
代碼第4行方括號內部的 n 不能省略。變長數組的長度是在執行時計算數組的長度的。變長數組也可以時多維的。
10. 函數的嵌套調用
# include<stdio.h> int main(int argc, char *argv[]){ int array[10] = { 2,1,0,3,6,5,4,7,9,8}; int ModifyNumber(int a[],int i); void show(int a[], int n); show(array,10); ModifyNumber(array,3); printf("The value has been updated. Please check: n"); show(array,10); return 0; } int ModifyNumber(int a[],int i){ void PrintMsg(); PrintMsg(); scanf("%d",&a[i]); return 0; } void PrintMsg(){ printf("Please input a new value:n"); } void show(int array[], int n){ for (int i = 0; i < n; i++){ printf("Array[%d]: %dn", i, array[i]); } } /* Array[0]: 2 Array[1]: 1 Array[2]: 0 Array[3]: 3 Array[4]: 6 Array[5]: 5 Array[6]: 4 Array[7]: 7 Array[8]: 9 Array[9]: 8 Please input a new value: 90 The value has been updated. Please check: Array[0]: 2 Array[1]: 1 Array[2]: 0 Array[3]: 90 Array[4]: 6 Array[5]: 5 Array[6]: 4 Array[7]: 7 Array[8]: 9 Array[9]: 8 */
在 C 語言種,允許定義函數互相調用(在一個函數種調用另外一個函數),但是函數嵌套定義(在一個函數種定義另外一個函數)是不允許的。類似於下面的函數定義,能通過系統編譯,但是程序無法正常執行:
# include<stdio.h> int main(int argc,char *argv[]){ void SendMsg(); void PrintMsg(); SendMsg(); PrintMsg(); return 0; } void SendMsg(){ void PrintMsg(); PrintMsg(); printf("This function is SendMsg.n"); } void PrintMsg(){ void SendMsg(); SendMsg(); printf("This function is PrintMsg.n"); }
這是一種間接遞歸的形式,必須保證兩個函數能正常終止。
11. 靜態變量
# include<stdio.h> int main(int argc,char *argv[]){ int Sta(int); int n; scanf("%d",&n); printf("First value: %dn",Sta(n)); printf("Second value: %dn",Sta(n)); return 0; } int Sta(int n){ static int b = 0; b = b + n; return b; } /* 6 First value: 6 Second value: 12 */
在 Sta() 函數第二次被調用時,靜態變量 b 的值已經是6。也就是說,靜態變量對其他函數隱藏數據,為將來再次調用保留這些數據。
12. 局部變量和外部變量
# include<stdio.h> int main(int argc,char argv[]){ void test(); extern int i; test(); printf("%dn",i); return 0; } int i = 1; void test(){ int j = i; int i =2; printf("%dn",j); } // 1 // 1
代碼是合法的。如果去掉關鍵字 extern, 那麼第二個打印的值將是0。