標準C基礎知識筆記四

honghu79 12年前發布 | 2K 次閱讀 DK1 google應用商城


 定義數組要指定元素的個數(固定的)
 數組名代表什么數組,當作為數值來用時,表示數組第一個元素;
 下標一定比元素個數少1
 盡量避免越界
 一般來說多維能解決的問題,用一維數組也能解決
 *(a+i);//這個是地址的加法  相當于a+i*sizeof(int)

 對于char數組可以存放字符串,但是必須有\0結尾標志

 ^D,輸入結束


 strcmp();用來比較兩個字符串
 strcpy只能用于字符串賦值
 strct在某一個字符串追加一個字符串
 “字符串”是存儲在只讀存儲器中的,只有系統能訪問不能修改。===》如果修改的話,會出現段錯誤
 strlen(...)
 strcmp(...,...)  相等0,左邊大為正,左邊小為負(比較的是ascii碼)
 strchr  從左往右查找字符串
 strrchr 從右往左查找字符串
 strstr 從字符串中查找字符串

 結構的對齊與補齊
 聯合(共用體)
 函數

 vi struct.c

 #include <stdio.h>
 typedef struct Goods{
  char name[18];//18個字節
  double price;//8個字節
  char special;//1
  int num;//4個字節
  short saled;//2個字節
 }gs;
 int main()
 {
  gs a[10];//定義一個Goods的變量數組,不用初始化,可以通過鍵盤來輸入
  printf("%d\n",sizeof(gs));//查看gs類型占用多少字節的存儲空間
  //對齊;一般來說一個變量分配空間的時候都會考慮分配內存邊界上,
  //一個變量的占用的內存地址,一般是這個變量占用的字節的倍數;
  //雖然這樣看起來有點浪費,但是訪問起來速度快
  //char隨便一個地址就可以訪問;short為2的倍數,int為4的倍數;double為8的倍數
  //一般編譯器超過4,也按照4的倍數來訪問

  return 0;
 }

 對齊規則:每個成員都從本身長度的倍數開始
 -------------------------------------------------------
 | name 18 | 空2|price 8|special 1| int num 4|    空 4|
 -------------------------------------------------------

 補齊:是為了多個元素挨著擺放時,也能滿足對齊規則

 為什么要對齊和補齊呢?(不同的OS,其尋址是不一樣的)
 32位的操作系統在訪問數據的時候都是從內存中按照4的倍數來訪問數據。

 數組的元素的內存存儲地址不一定是連續的,可能存在間隙;


 位斷:
 由于內存分配是按照幾個字節來分配的。但個別時候可能只需要幾個位即可;C語言可以設置為某幾個
 成員用幾個位

 //一般會用在嵌入式開發中。每一個位控制一個東西,控制一個管腳
 #include <stdio.h>

 struct mode{//比如用戶的讀寫執行權限rwxrwxrwx
  unsigned char userread:1;
  unsigned char userwrite:1;
  unsigned char userexecute:1;
  unsigned char groupread:1;
  unsigned char groupwrite:1;
  unsigned char groupexecute:1;
  unsigned char otherread:1;
  unsigned char otherwrite:1;
  unsigned char otherexecute:1;
  unsigned char f3:3;
  unsigned int f10:10;
 };
 int main()
 { 
  struct mode m={1,1,0,1,0,0,1,0,0,6,999};//初始化
  printf("size:%d\n",sizeof(m));
  printf("%d%d%d,%d%d%d,%d%d%d",
  m.userread,m.userwrite,m.userexecute,
  m.groupread,m.groupwrite,m.groupexecute,
  m.otherread,m.otherwrite,otherexecute
  );
  printf("%d,%d\n",m.f3,m.f10);
  
  return 0;
 }

 //備注:在vi下替換某幾行內的某個字符串user為另一個字符串other
 //   :10,12s/user/other/

 
 
 聯合union
 所有成員共用一塊地方(共用體),操作任何一個都會影響其他的。
 那么什么時候用聯合呢?這些成員總是只用一個。

 #include <stdio.h>
 union IP{
  char i4[4];
  int net;
   //可以使用192.168.x.x格式來表示IP;也可用一個整數來表示一個IP地址
 };

 int main()
 {
  printf("sieze:%d\n",sizeof(union IP));
  IP me{192,168,0,20};
  printf("%x\n",me.net);
  
  me.net=0x12345678;
  int i;
  for (i=0;i<4;i++)
   printf("%d ",me.i4[i]);
  printf("\n")
  return 0;
  
 }
 
 不同系統,其存儲方式也是不一樣的,有的是小端存儲有的是大端存儲
 
 C語言本身就是一個函數語言;把實現某一個功能的打個包==》函數
 
 printf scanf strcpy strlen strcat....標準C里面的標準庫函數
 
 vi function.c
 #include <stdio.h>
 
 int main()
 {
  int n=Main(); //Main()帶回一個數值10
  printf("hello world!\n");
  n+=Main();
  return 0;
 }
 
 int Main()//函數名是區分大小寫的
 {
  printf("你好 世界\n");
  return 10;
 }
 
 一個C語言只有一個main函數,也是程序的入口,可以在main函數內調用其他函數。
 
 寫一個函數清輸入緩沖區
 
 #include <stdio.h>
 
 void clear();//函數聲明;
 int main()
 {
  char name[20];
  char gender;
  printf("請輸入姓名:");
  scanf("%s",name);
  clear();//這個決定了要把void clear()函數放到前面;負責會出現隱式聲明錯誤;
  printf("請輸入性別(M/F):");
  scanf(" %c",&gender);//理解為什么在" %c"有一個空格;因為上面輸入姓名之后肯定要敲個回車來確定輸入。但這個回車會留在輸入緩沖區中;會影響下面的輸入。
  //所以要加個空格來解決這個問題
  printf("%s:%c\n",name,gender);
 }
 
 void clear()//void代表這個函數不帶東西回來;函數體
 {
  scanf("%*[^\n]");
  scanf("%*c");
  
 }
 C語言中對于不認識的類型,一般會默認的為int類型(隱式聲明)


 函數定義:函數名、函數聲明、函數體
 函數調用:
 
 
 從鍵盤輸入一個指定范圍內的整數(get5,80)
 
 #include <stdio.h>
 int get(int a,int b)//形參(定義的時候使用)
 {
  printf("請輸入兩個整數:\n");
  printf("a=%d,b=%d\n",a,b);
  int n;//這里的n與main里面的n是不同的n。在不同的{}號的是不同的。
  do{
   printf("請輸入%d到%d的一個整數:",a,b);
   //scanf("%d",&n);//切記:在這里%d后面沒有\n
   if(scanf("%d",&n)!=1){
    scanf("%*[^\n]*c");
    //進一步判斷輸入的a<b,如果a>b,則需要交換數值
    //判斷輸入的是整數而非小數或字符    
   }
  }while(n<a||n>b);

  return (a+b)/2;
 }
 int main()
 {
  int n=get(1,100);//實參(調用的時候使用)
  int m=get(10,50);
  printf("n=%d,m=%d\n",n,m);
  return 0;
 }
 
 
 ******************************************************
 
 
 寫一個函數在多個程序里面能夠使用(函數調用);
 ------------------------------------
 編寫一個程序里面帶clear函數
 vi  clear.c
 #include <stdio.h>
 void clear(){
  scanf("%*[^\n]");
  scanf("%*c");
 }
 
 
 編寫一個聲明clear函數
 vi  func_clear.h
 
 void clear();//前面已經寫了一個clear函數,在這里只是寫一個函數聲明
 
 
 在寫的程序里面調用這個函數
 vi param.c
 #include <stdio.h>
 #include "func_clear.h"  //函數的聲明
 int main()
 {
  clear();
  return 0;
 }
 
 
 //把聲明插入一份就行了。

 一個程序兩個文件怎么來編譯呢?==》分開編譯,連接
 編譯:
 gcc -c clear.c  //只編譯
 gcc -c param.c
 gcc clear.o param.o//合在一起,誰前誰后無所謂

 
 man gcc
 
 
 每一個頭文件感興趣就可以man下看看到底是怎么回事。
 一般.h文件都在/user/include目錄下
 
 
 //寫一個小程序來觀看函數調用
 //輸入一行文字
 //將其中的數字轉換成對應的漢字,小寫字母變成大寫,其他不變
 
 vi  check.c
 #include "check.h" //把函數聲明插進來
 bool isLower(char c)
 {
  return(c>='a'&&c<='z');
 }
 
 bool isNum(cha c)
 {
  return(c>='0'&&c<='9');
 }
 
 vi check.h
 //函數聲明
 typedef enum bool{true=1,false=0}bool;//c語言里面并沒有bool類型,定義一個類型
 bool isLower(char c);
 bool isNum(char c);
 
 轉換函數
 
 vi  convert.c
 #include <stdio.h>

 char toUpper(char c) //把小寫轉換成大寫
 {
  return(c-'a'+'A');  //c-'a'字符在字母表中的偏移量;+'A'在大寫字母中的偏移量
 }
 
 char* toChinese(char c) //漢字是一串字符,而非一個字符;操作字符串,只要知道數組的開始地址即可。
 {
  char num[10][5]={"零","一","二","三","四","五","六","七","八","九"};
  //這樣定義的含義?10個一維數組,每個一維數組
  printf("%s",num[c-'0']);
  return(num[c-'0']);//基本上沒作用;變量是有范圍的
  //'0',數字為48;c-'0'
 }
 
 vi convert.h
 
 char toUpper(char);
 char* toChinese(char);
 
 
 
 #include <stdio.h>
 #include "check.h"
 #include "convert.h"
 int main()
 {
  char c;
  printf("請輸入一行文字:");
  do{
   scanf("%c",&c);
   if (islower(c))
    printf("%c",toupper(c));
   else if(isnum(c))
    printf("%s",tochinese(c));
   else
    printf("%c",c);
  }while(c!='\n');
  return 0;
 }
 
 
 vi charaddr.c
 #include <stdio.h>
 
 int main()
 {
  char a[100]="good afternoon,everyone!";
  char* p=a+5;//a+5===>&a[5],在這里兩者是等價的
  printf("%s\n",p);
  return 0;
  
 }
 
 問題:
 //判斷某年有多少天
 //日期是否有效日期;
 //日期是這一年的第幾天
 //日期是這一年的第幾周的哪一天
 
 函數:
  單一定義原則;
  函數多次聲明;
  
常用的C語言標準庫文件  
 stdio.h  //輸出輸入
 stdlib.h //工具
 time.h  //時間相關
 math.h  //數學相關
 string.h  //字符和內存操作
 ctype.h  //字符操作
 
 
 
 局部變量和全局變量
 
 #include <stdio.h>
 #include <string.h>
 
 char w[7][10]={"星期日","星期一","星期二","星期三","星期四","星期五","星期六"};
 //這種變量為全局變量(無什么范圍限制;在C里面先聲明后使用)
 
 //也可以使用extern來聲明,告訴編譯器,w在其他地方有定義;
 
 //extern char w[7][10];
 char* week(int);
 char* weekday(int n)
 {
  return w[n];  
 }
 int main()
 {
  printf("%s\n",weekday(3));
  strcpy(week(5),"fr");//通過week(5)知道其地址,然后重新賦值
  printf("%s\n",week(5));
  return 0;
 }
 
 vi weekday.c
 #include <stdio.h>
 //下面這句配合extern來使用
 char w[7][10]={"星期日","星期一","星期二","星期三","星期四","星期五","星期六"};
 char e[7][10]={"Sunday","Monday",...};
 //通過這種方式也可以實現多語言的支持
 //static h[7][10]={,,,,};//static限制全局變量只能在本文件中使用,對外隱藏
 
 void showweekday(int n)
 {
  printf("%s\n",weekday(5));
  printf("%s\n",e[2]);
  return 0; 
 }
 char* week(int n)//構建一個函數,讓外界通過調用這個函數來訪問static全局變量
 {
  return h[n];
 }
 文件本身并不限制全局變量的范圍;static可以限制全局變量只能在本文件中使用
 但是其他文件怎么能訪問這個static的全局變量呢,可以構建一個函數,通過調用函數的方式即可
 strcpy(week(5),"fr");
 全局函數只能在本文件中使用也是加static
 
 
  #include <stdio.h>
 #include <string.h>
 
 
 char* weekday(int n)
 {
  static char w[7][10]={"星期日","星期一","星期二","星期三","星期四","星期五","星期六"};
  return w[n];  
 }
 int counter()
 {
  int cnt=0;
  //static int cnt=0;
  //靜態局部變量,第一次使用的時候分配空間,一直保留直到程序結束。static局部變量只初始化一次。
 
  return ++cnt;
 }
 
 int main()
 {
  printf("%s\n",weekday(3));
  int i;
  //auto signed int i;//自動,基本不用。
  for (i=0;i<5;i++)
   printf("%d\n",counter());
  return 0;
 }
 
 由于全局變量并不安全,所以程序里面盡量少用全局變量。
 靜態全局變量和局部變量不會有垃圾數據,要么是0要么是指定的數據。
 
 time:從1970.1.1 00:00:00計算到現在的時間的秒數
 
 
 register寄存器---請求把變量放到寄存器中而不是內存中;寄存器比內存快
  寄存器是沒有地址的;通過&i取地址會報錯。
 #include  <stdio.h>
 
 int main()
 {
  register int i=100;//register是一個使用寄存器的請求,用不用不一定
  printf("%d\n",i);
  return 0;
  
 }
 
 volatile int n;//這個變量可能會隨時被莫名其妙的修改
 一般會用在嵌入式開發中,可能由某個硬件直接來控制(如傳感器)。
 
 

 本文由用戶 honghu79 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!