學生時代所學的一些 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。