日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

C语言程序设计案例式教程

發布時間:2023/12/20 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C语言程序设计案例式教程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

C語言程序設計案例式教程

數據類型與運算符

  • 變量的數據類型 :整形變量,實型變量,字符型變量,枚舉類型變量; (單引號內只可以存放轉義字符、一個字符)

    數據類型所占字符數
    char1個字節
    int4個字節
    short2個字節

    枚舉類型變量:eg:enum 枚舉名{標識符1=整型常量1,標識符2=整型常量 2,…}

  • printf()函數與scanf()函數
    (1) 常用printf()函數格式字符

    用格式字符含義注意
    %s輸出一個字符串
    %c輸出一個字符ACSLL碼大寫字母=小寫字母+32
    %d以十進制輸出一個有符號整型
    %u以十進制輸出一個無符號整型eg:3為整數,3.為小數
    %f以十進制輸出一個浮點數小數類型輸出默認小數點后六位
    • sizeof運算符可以獲取數據字節數 : sizeof(數據類型名稱或變量名稱)
      eg:printf(“int: %d字節\n”,sizeof(int));
    • 格式字符串一般形式:[標志][輸出最小寬度][.精度][長度]類型
      (2) scanf()函數
      功能:接收用戶輸入,也可以通過格式控制字符控制用戶輸入
      接收的是變量的地址
    • scanf("%d,%d",&a,&b) 輸入數據用逗號隔開
      scanf("%d%d",&a,&b) 輸入數據用空格隔開
      (3)算數運算符優先級
      (4)位運算符
      (5)關系運算符
      (6)三目運算符
      表達式1?表達式2:表達式3(若1為真,則為2,否則為3)
      條件運算符方向:自右向左
      eg:a>b?a:c>d?c:d應理解為a>b?a:(c>d?c:d),這也是三目運算符的嵌套

    結構化設計程序

  • if語句
    單分支結構:if…
    雙分支結構:if…else…
    多分支結構:if…else if…else…

  • switch條件語句(條件語句)

    - switch(表達式) - { - case 目標1: - 執行語句 1; - break; - case 目標2: - 執行語句 2; - break; - case 目標n: - 執行語句 n; - break; - default: - 執行語句 n+1; - break; - }
  • break語句(跳轉語句)
    終止當前循環,執行循環體外的第一條語句

  • continue語句(跳轉語句)
    中止本次循環,并繼續執行下一次循環;
    break語句可以用于switch語句,而continnue不可以;

  • goto語句(跳轉語句)
    break語句出現在嵌套循環中的內層循環,只能跳出內層循環;如果想跳出外部循環則需要對外層循環添加標記,然后使用goto語句。

  • while循環語句與 do…while循環語句
    循環條件的值非0,循環體就會被執行;循環體執行完畢時會繼續判斷循環條件,知道循環條件的值為0時,整個循環過程才會結束。 do…while循環語句與之類似。
    不同的是,do…while循環體先執行后判斷(while先判斷后執行)

  • ... while(1) {scanf("%d",&choice);switch(choice){case 1:...break;case 2:...break;case 3:exit(0);break;} }
  • for循環結構語句
    - for(初始化表達式;循環條件;操作表達式)
    - {
    - …
    - }
  • 隨機數(rand()函數,srand()函數)
    (1)rand()函數(一次性的)
    生成一個無范圍限制的隨機數,只需使用rand()即可,rand()會返回一個隨機數0~RAND_MAX(2147483647)。
    生成某個范圍的隨機數:
  • 范圍寫法
    0~10rand()%10(利用函數對10取余)
    5~25rand()%20+5(利用函數對25-5=20取余再加上5)

    (2)srand()
    稱為隨機數生成的初始化器
    函數原型:void srand(unsigned int seed);

    #include <stdio.h> #include <time.h> #include <stdlib.h> int main() {srand((unsigned int)time(NULL));int b1, b2, i;b1=b2=0;for(i=0;i<4;i++){b1=b1+rand()%6+1;b2=b2+rand()%6+1;}if(b1>b2)printf("b2 go\n");else if(b1<b2)printf("b1 go\n");elseprintf("please again\n");return 0; }
  • 自守數(某個數末尾平方的幾位等于該數)
  • 在這里插入代碼片
  • 回文素數(窮舉法)
  • 函數

  • 函數的定義
  • 函數包括含義
    返回值類型限定函數返回值的數據類型
    參數名函數的名稱
    參數類型限定調用函數時傳入函數中的數據類型
    參數接收傳入函數中的數據
    return關鍵字用于結束函數,將函數的返回值返回函數調用處
    返回值被return語句返回的值
  • 函數調用時的數據傳遞:形式參數,實際參數

  • 內存四區:
    (1)棧區: 對一個程序來說,棧區是一塊連續的內存區域,該區域由編譯器自動分配和釋放,一般用來存放函數的參數、局部變量等,由于棧頂的地址和棧區的最大容量是由系統預先規定的,因此這塊區域的內存大小固定。若申請的內存空間超過棧區的剩余容量,則系統會提示溢出。
    (2)堆區:對一個程序來說,堆可以是不連續的內存區域,此段區域可以=由程序開發者自主申請,其使用比較靈活,但缺點是同樣需要程序開發人員自主釋放,若程序結束時該段空間仍未被釋放,就會造成內存泄露,最后由系統回收。
    (3)數據區
    根據其功能,數據區又可分為靜態全局區和常量區兩個城。
    全局區是用于存儲全局變量和靜態變量的區域,初始化為非0的全局變量和靜態變量在一塊區域,該區域稱為data段;未初始化或者初始化為0的全局變量和靜態變量在相鄰的一塊區城,該區域稱為bss段。該區域在程序結束后由操作系統釋放。
    常量區用于存儲宇符事常量和其他常量,該區域在程序結束后由操作系統釋放。
    (4)代碼區:代碼區用于存放函數體的二進制代碼。程序中每定義一個函數,代碼區都會添加該函數的二進制代碼,用于描述如何運行函數。當程序調用函數時,會在代碼區尋找該函數的二進制代碼并運行。

  • 局部變量與全局變量
    (1)局部變量:定義在函數內部的變量,變量的作用域僅限于函數內部,函數執行完畢以后這些變量就失去作用。
    (2)全局變量:在所有函數(包括主函數)外部定義的變量成為全局變量,他不屬于某個函數,而是屬于源程序,因此全局變量可以為程序中的所有函數共用,他的有效范圍是從定義開始處到源程序結束。
    若在同一個文件中,局部變量和全局變量同名,則全局變量會被屏蔽,在程序的局部暫時使用局部變量保存的數據。

  • int a; //a為全局變量 int main() {return 0; }
  • 函數調用
    (1)主函數調用普通函數
    (2)嵌套調用
    主函數可以調用其他普通函數,普通函數可以相互調用,但是不能調用主函數
    (3)調用方式
  • 調用方式舉例
    將函數作為表達式調用int a=max(1,2)
    將函數作為語句調用printf(“hello \n”);
    將函數作為實參調用printf("%d\n",max(1,2));
  • 內部函數與外部函數
  • 內部函數外部函數
    關鍵字staticextern
    函數形式static 返回值類型 函數名(參數列表){}extren 返回值類型 函數名(參數列表){} eg:extren int add(int a,int b){}
    意義又被稱為靜態函數,指該函數僅在本文件有效可省略extren,仍可被其他文件調用
  • 遞歸(即程序對自身的調用)
    需要注意兩點:遞歸公式和邊界條件(或終止條件)
    eg:(兔子數列或斐波那契數列或黃金分割數列)(存在錯誤)
  • #include<stdio.h> int getnum(int n) {if(n==1||n==2)return 1;return getnum(n-2)+getnum(n-1); } int main() {printf("f(1)=%d\n",getnum(1));printf("f(1)=%d\n",getnum(1));printf("f(1)=%d\n",getnum(1));printf("f(1)=%d\n",getnum(1));printf("f(1)=%d\n",getnum(1));printf("f(1)=%d\n",getnum(1));return 0; }

    數組

  • 一維數組
    (1)定義:數據類型 數組名[常量表達式];
    eg:int array[5]; (占據內存大小為:5*sizefo(int))
    (2)初始化常見方式:
  • 方式舉例
    直接對數組中所有元素賦值int s[4]={1,2,3,4};
    只對數組中一部分元素賦值int s[5]={1,2} ; (其他元素的值會被默認設置為零)
    對數組全部元素賦值int[]={1,2,3} (系統會根據賦值號右邊初始值列表給出的初值個數自動設置數組的長度)

    (3)引用方式:數組名[下標];
    (4) 數組的非法操作

    • 不能用已經初始化的數組為另一個數組賦值
      eg:int a[3]={1,2,3}; int b[3]; y=x;

    • 不能對數組進行整體的輸入輸出,必須以元素為單位進行操作
      printf()和scanf()只支持字符數組整體的輸入輸出

    • 數組和數組之間不能進行比較,也不能進行運算

  • 二維數組
    (1)語法格式:類型說明符號 數組名 {常量表達式1}{常量表達式2};
    (2)初始化
  • 方式舉例
    按行給二位數組賦初值int a[2][3]={{1,2,3},{4,5,6}};
    將所有的數組元素按順序寫在一個大括號里int a[2][3]={1,2,3,4,5,6};
    對部分數組元素賦初值int a[3][3]={{1},{2,3,4},{5,6}};(對沒有賦值的元素,系統會自動賦值為0)

    二維數組的第一個下標可省略,第二個下標不可省略
    (3)引用(同一維數組一樣)

  • 數組作為函數參數
  • func(int arr[3]); func(int arr[],int n);

    必須保證形參和實參的數組類型是相同的

  • 冒泡排序法
    冒泡排序法便是最經典的排序算法之一,作為入門級排序算法,最適合編程新手學習。
    對于從小到大的冒泡排序,通俗來講;不斷地比較數組中相鄰的兩個元素,較小者向上浮,較大者往下沉,整個過程和水中氣泡上升的原理相似。
    以從小到大排序為例,分步驟講解冒泡排序的整個過程,具體如下:
    (1)從第一個元素開始,依次將相鄰的兩個元素進行比較,直到最后兩個元素完成比較。如果前一個元素比后一個元素大,則交換位置。整個過程完成后,數組中最后一個元素就是最大值,這樣便完成了第一輪的比較;
    (2)除了最后一個元素,將剩余的元素繼續進行兩兩比較,過程與第(1)步相似,這樣便可以將數組中第二大的數放在倒數第二個位置;
    (3)以此類推,重復上面的步驟,直到全部元素從小到大排列為止。
    eg:
  • ... void bubblesort(int s[],int n) {int i,j,temp;for(i=0;i<n-1;i++){for(j=0;j<n-j-1;j++){if(s[j]>s[j+1]){temp=s[j];s[j]=s[j+1];s[j+1]=temp;}}} }

    指針

  • 定義指針變量的語法格式:變量類型* 變量名(變量名前的符號‘*’表示該變量為一個指針)
    eg:int *p
  • 指針變量的初始化
    (1)接收變量的地址為其賦值,也可在定義時賦值
  • int a=11; //定義一個int型的變量a int* p; //定義一個int*型的指針變量p p=&a; //使int.型的指針變量p指向int型變量a所在的存儲空間 int a=10; //定義一個int型的指針變量a,并初始化為10 int* p=&a; //定義一個int*型的指針變量p,并初始化為變量a的地址

    (2)與其他指針變量指向同一塊存儲空間

    int* p; //定義一個int型的指針變量p p=q; //使int型的指針變量p與q指向同一塊存儲空間
  • 指針的引用
    格式:*指針變量名
  • int a=10; int* p=&a; printf("%d\n",&a); //輸出指針變量指向的地址中存儲的數據(間接訪問) //printf("%d\n",a); //直接訪問

    只能使用間接訪問的場合

    場合原因
    用戶申請一塊內存空間時因為該空間沒有對應的變量名,所以只能通過首地址對其進行訪問
    通過被調函數改變主調函數變量的值由于值只能由實參向形參單向傳遞,所以被調函數無法通過改變形參的值去改變主調函數中變量的值,只能通過間接訪問指針指向的內存空間來改變主調函數的值。
  • 指針類型
    (1)空指針(沒有指向任一儲存單元的指針)
  • int* p1=0 //0是唯一一個不用轉換就可以賦值給指針的數據 int*p2=NULL; //NULL是一個宏定義,起作用與零相同 //在ASCLL碼中編號為零的字符就是空

    一般編程時,先將指針初始化為空,在對其進行賦值操作

    int x=10; int *p=NULL; //是指針指向空 p=&x;

    (2)無類型指針(使用該指針為其他基類指針賦值,必須先轉換成其他類型的指針,使用該指針,接收其他類型指針不需要強轉)

    void* p=NULL,*q; int* m=(int* )p; int a=10; q=&a;

    (3)野指針:指向不可用區域的指針。形成原因有以下兩種:

    • 指針變量沒有被初始化。定義的指針變量若沒有被初始化,則可能指向系統中任意一塊存儲空間,若指向的存儲空間正在使用,當發生調用并執行某種操作時,就可能造成系統崩潰,因此在定義指針時應使其指向合法空間。
    • 若兩個指針指向同一塊存儲空間,指針與內存使用完畢之后,調用相應函數釋放了一個指針與其指向的內存,卻未改變另一個指針的指向,將其置空。此時未被釋放的指針就變為野指針。
      在編程時,可以通過“if(p==NULL){}"來判斷指針是否指向空,但是無法檢測該指針時否為野指針,所以要避免野指針的出現。
  • 指針的交換
    根據指針可以獲得變量的地址,也可以得到變量的信息,所以指針交換包含兩個方面,一是指針指向交換,二是指針所指地址中存儲數據的交換。
    ( 1)指針指向交換
    若要交換指針的指向,首先需要申請一個指針變量,記錄其中一個指針原來的指向,再使該指針指向另外一個指針,使另外一個指針指向該指針原來的指向。假設p和a都是int型的指針,則其指向交換示意圖如圖所示。

    具體的實現方法如下:
  • int *tmp=NUIL; //創建輔助變量指針 tmp=p; //使用輔助指針記錄指針口的指向 p=q; //使指針p記錄指針q的指向 g=tmp; //使指針q指向p原來指向的地址

    (2)數據的交換
    若要交換指針所指空間中的數據,首先需要獲取數據,獲取數據的方法在案例一中已經講解,即使用“*”運算符取值。假設p和a都是int型的指針,則數據交換示意圖如圖所示。

    int tmp=NUIL; //創建輔助變量 tmp=p*; //使用輔助變量記錄指針p指向的地址中的數據 p=q; //使指針p指向地址中的數據放到q所指地址中 p=tmp; //將p中原來的數據放到q所指地址中
  • 指針和一維數組
  • 一個普通的變量有地址,一個數組包含若干個變量,數組中的每個元素都在內存中占據存做單元,所以每個元素都有各自的地址。指針可以通過變量的地址訪問相應的變量,當然也可以根據指針的指向來訪問數組中的元素。
    以int型數組為例,假設有一個int型的數組,其定義如下:

    int a[5]={1,2,3,4,5};

    若要使用指針指向數組中的元素,則其方法如下;

    int* p=NULL; p=&a[0]; //也可寫作p=a,是指針指向數組的首地址

    過指針訪問數組中的其他元素,必須先定義一個指向該數組的指針

    本條定義語句與之前的賦值語另外需要注意的是,數組名是一個地址,在為指針賦值時不可再對其進行取址操作。本條賦值語句將數組的數組名賦給了指針p,此時p與數組名等價,所以可以像使用數組名一樣,使用下標取值法對數組中的元素進行取值,其表示為p[下標]
    下標取值法指針的實質就是地址,其實對地址的加減運算并無意義,地址的值也不允許隨意修改,但是當指針指向數組元素時,對指針進行加減運算能大大提高指針的效率。
    若數組指針與一個整數結合,則執行加法操作,例如對以上定義的,指向數組a的指針p,使p=p+1,則指針p將會指向數組中當前位置的下一個元素,即指向數組a1中的元素al1]。這是因為針對數組中的元素執行p+1操作時并非將地址的值進行簡單的加1,而是根據數組元素的類型,加上一個元素所占的字節數。在本次p=p+1時,指針實際上加了4個字節(一個int型數據所占的字節),若指針p存儲的 P存儲的地址原本為0x2016,則運算后的指針存儲的地址變為0x2020。
    舉例:
    假設此時指針p指向數組元素a[0],若要使用指針獲取數組元素a[2)的值,可以使用如下兩種方式。
    (1)移動指針,使指針指向a[2],獲取指針指向元素的值:

    p=p+2; printf (" &d",*p);

    (2)不改變指針指向,通過數組元素指針間的關系運算指針并取值:

    printf("%d",*(p+2));

    設要獲取數組a中的元素a[3],則使用下標法和指針法取值的方式分別如下;

    p[3] //下標取值法 *(p+3) //指針取值法

    (3)當指針指向數組元素時,還可以進行減法操作。
    此時指針類型相同,因此相減之后的結果為數組元素類型字節長度的倍數,根據這個數值,可以計算出兩個元素之間相隔元素的個數.
    比如此時指針p1指向數組元素 a[1],指針p2指向數組元素a{3],則執行以下操作,

    (p2-p1)/sizeof (int);

    得到的結果為2,表示p1和p2所指的元素之間相隔兩個元素,如此一來,不需要具體地知道兩個指針所對應的數據,就可以知道它們的相對距離。
    兩個指針(地址)相加沒有意義

  • 內存分配
    在程序執行的過程中,為保證程序能順利執行,系統會為程序以及程序中的數據分配一定的存儲空間。但是有些時候,系統分配的空間無法滿足要求,此時需要編程人員手動申請堆上的內存空間來存儲數據。
    C語言中申請空間常用的函數為: malloc()函數、calloc()函數和realloc()函數,這三個函數包含在頭文件"stdlib.h"中,都能申請堆上的空間。
    (1) malloc()函數
    malloc()函數用于申請指定大小的存儲空間,其函數原型如下:
  • void* malloc(unsigned int size);

    在該原型中,參數size為所需空間大小。該函數的返回值類型為void*,使用該函數申請空間時,需要將空間類型強轉為目標類型。假設要申請一個大小為16字節、用于存儲整型數據的空間,則公式如下:

    int* s=(int*) malloc (16);

    當為一組變量申請空間時,常用到sizeof運算符,該運算符常用于求變量或數據類型在中所占的字節數。在調用malloc()等函數時使用sizeof運算符,可以在已知數據類型和數據數量的前提下方便地傳入需要開辟空間的大小。假設為一個包含8個int型數據的數組申請存儲空間,其方法如下所示:

    int* arr= (int*) malloc (sizeof (int) *8);

    (2) calloc()函數
    calloc()函數與malloc()函數基本相同,執行完畢后都會返回一個void*型的指針,只是在傳值的時候需要多傳入一個數據。其函數原型如下:

    void* calloc(unsigned int count,unsigned int size);

    calloc()函數的作用比malloc()函數更為全面。經calloc()函數申請得到的空間是已被初始化的空間,其中數據全都為0,而malloc()函數申請的空間未被初始化,存儲單元中存儲的數據不可知。另外calloc()在申請數組空間時非常方便,它可以通過參數size設置為數組元素的空間大小,通過參數將count設置為數組的容量。
    (3) realloc()函數

    realloc()函數的函數原型如下:

    void* realloc (voia* memory, unsignea int newsize);

    realloc()函數的參數列表包含兩個參數,參數memory為指向堆空間的指針,參數newSize為新內存空間的大小,realloc()函數的實質是使指針memory指向存儲空間的大小變為newSize.
    如果memory原本指向的空間大小小于newSize,則系統將試圖合并memory與其后的空間,著能滿足需求,則指針指向不變;如果不能滿足,則系統重新為memory分配一塊大小為newsize的空間。如果memory原本指向的空間大小大于或等于newsize,將會造成數據丟失。

  • 內存回收
    需要注意的是,使用malloc()函數、calloc()函數、realloc()函數申請到的空間都為堆空間,程序結束之后,系統不會將其自動釋放,需要由程序員自主管理。" C語言提供了free()函數來釋放由以上幾種方式申請的內存, free()函數的使用方法如下;
  • int* p= (int*) malloc (sizeof (int)*n); free (p);

    ==若用戶申請的堆空間沒有及時回收,可能會導致內存泄漏。==內存泄漏也稱為“內存滲漏”,釋放使用動態存儲分配函數開辟的空間,在使用完畢后若未釋放,將會一直占據該存儲單元,直到程序結束。
    若發生內存泄漏,則某個進程可能會逐漸占用系統可提供給進程的存儲空間,該進程運行時間越長,占用的存儲空間就越多,直到最后耗盡全部存儲空間,導致系統崩潰。
    內存泄漏是從操作系統的角度考慮的,這里的存儲空間并非指物理內存,而是指虛擬內存大小,這個虛擬內存大小取決于磁盤交換區設定的大小。由程序申請的一塊內存,如果沒有指針指向它,那么就說明這塊內存泄漏了。

  • 快速排序
  • 設要排序的數組是S[0]…S[N-1],首先任意選取一個數據(通常選用數組的第一個數)作為關鍵數據,然后將所有比鍵值小的數都放到鍵值之前,所有比鍵值大的數都放到鍵值之后,這個過程稱為一趟快速排序。一趟快速排序的算法步驟如下:
    (1)設置兩個變量low. high,排序開始的時候: low=0, high=N-1;
    (2)以第一個數組元素作為關鍵數據,賦值給key,即key=S[0]:
    (3)從high開始向前搜索,即從后向前搜索(high-- ),找到第一個小于key的值S[high]
    將S[high]和S[low]互換;
    (4)從low開始向后搜索,即從前向后搜索(low++ ),到第一個大于key的值Slow.
    將S[low]和S[high]互換:
    (5)重復步驟(3),( 4),直low>=high為止。
    需要特別注意的是,若在第(3), (4)步中,沒找到符合條件的值,即(3)中S[high]不4于ney, (4) 中S[low]不大于key時,改變high, low的值,使得high=high-1, low=low+1 直至找到為止。找到符合條件的值,進行交換時,low, high指針位置不變。

    • 指針與二維數組
      (1)使用指針引用二維數組

    • eg:數組中的數據類型為int,每行有n個元素,則數組指針每加1,指針實際移動的步長為: n*sizeof(int).

    • 一般用數組名與行號表示一行數據。以數組a[2][3]={{1,2,3},{4,5,6}}為例, a[0]就表示第一行數據,a[1]表示第二行數據,a[0] a[1]相當于二維數組中一維數組的數組名,指向二維數組對應的第一個元素,a[0]=&a[0][0],a[1]=a[1][0]

    • a+i與"(a+i)的意義。通過之前一維數組的學習我們都知道""是它代表的是整行數據元素,只是一個地址,并不表示某一元素的值。""表示指針指向的地址存儲的數據。但在二維數組中, a+i雖然指向的是該行元素 一個地址行元素的首地址,但與a[i]等價。*(a+i)表示二維數組元素a[i][j]的地址,等價于&a[i][j],也等價于a[i]+j:

      二維數組中相關指針與數據的表示形式

    表示形式含義
    a二維數組名,指向一維數組a[0],為0行元素首地址,也是a[0][0]的地址
    a[i],*(a+i)一維數組名,表示二維數組第i行元素首地址,值為&a[i][0]
    *(a+i)+j二維數組元素地址,二維數組中最小數據單元地址,等價于&a[i][j]
    ((a+i)+j)二維數組元素,表示第i行第j列數據的值,等價于a[i][j]

    (2)作為函數參數的二維數組

    • 一維數組的數組名就是一個指針,若要將一維數組傳入函數,只需傳入數組名,==傳入的參數說明,應寫為int* arr,而不是int** arr,因為int** arr是一個二級指針,他聲明的是一個指向整形指針的指針,而非指向整形數組的指針。
    • 若將二維數組傳入函數,形式相對略為復雜。一維數組可以不關心數組中數據的個數,但二維數組既有行,又有列,在定義時行值可以缺省,列值不能缺省,所以將二維數組的指針傳遞到函散中時必須確定數組的列值。定義一個數組指針的形式:數據類型 (*數組指針名)[列號]
    int(* p)[5]=a; func(p);

    (3)函數指針

    • 函數指針的定義
      若在程序中定義了一個函數,編譯時,編譯器會為函數代碼分配一段存儲空間,這段空間起始地址(又稱入口地址)稱為這個函數的指針。
    • 與普通變量相同,同樣可以定義一個指針指向存放函數代碼的存儲空間的起始地址,這樣的指針叫做函數指針。函數指針的定義格式:返回值類型(*變量名)(參數列表)
      其中返回值類型表示指針所指函數的返回值類型,“*p”表示這是一個指針變量,參數列表表示該指針所指函數的形參列表。
    • 假設定義一個參數列表為兩個int型變量,返回值類型為int的函數指針,則其格式:int (p) (int,Int)
      “"的優先級較高,所以要將“變量名”用小括號括起來。
      (4)函數指針的用途
    • 調用函數,使用函數指針調用對應函數,方法與使用函數名調用函數類似,只需將函數名替換為“指針名”即可。假設要調用指針p指向的函數,其形式如下, (*p) (3,5)
      二是將函數的地址作為函數參數傳入其他函數。將函數的地址傳入其他參數,就可以在被調函數中使用實參函數。函數指針作為函數參數的示例如下:
    void func(int (*p) (int, int), int b, int c);

    字符串

  • 字符數組
    (1)字符數組的定義
  • char 數組名[常量表達式1][常量表達式2]; //二維數組 char 數組名[常量表達式1] ; //一維數組,char表示字符數據類型

    (2)字符數組的初始化
    在數組定義的同時,也可以對數組中的元素賦值
    元素個數不能多于字符數組大小
    初始值項少于數組長度,空余元素都會賦值為空字符‘\0’
    (3)字符串概念
    字符串是由數字、字母、下劃線和空格等各種字符組成的一串字符,是個常量,由一對英文半角狀態下的雙引號(" )括起來。字符串在末尾都默認有一個’\0’作為結束符。
    方法.

    • 用字符串初始化字符數組
    • 獲取字符串長度
      sizeof運算符也可以用來求字符串的長度,例如sizeof(‘abcde’)。還可以使用strlen()函數來獲取字符串長度, strten()函數原型如下:unsigned int strlen(char *s)
      其中s是指向字符串的指針,返回值是字符串的長度。需要注意的是,使用strlen()函數得到的字符串的長度并不包括末尾的空字符‘\0’
      strlen()與sizeof運算符的區別,具體如下:
    • sizeof()是運算符; strlen()是 C語言標準庫函數,包含在string.h頭文件;
    • sizeof()的功能是獲得所建立對象的字節大小,計算類型所占內存; strlen()時獲得字符串所占內存的有效字節數;
    • sizeof運算符的參數可以是數組、指針、類型、對象和函數;strlen()函數的參數是指向以’\0’結尾的字符串的指針;
    • sizeof()運算符計算大小在編譯時就完成,因此不能用來計算動態分配內存的大小,strlen()函數結果要在運行時才能計算出來。
  • 字符串與指針
    在C語言中,字符型指針用char*來定義,它不僅可以指向一個字符型常量,還可以指個字符串。
    字符數組與字符指針:字符串用字符數組存儲,也可以取數組地址賦值給字符型指針。以下為兩者的區別與聯系:
    (1)存儲方式
    字符數組在用字符串初始化時,這個字符串就存放在了字符數組開辟的內存空間中;而字符指針變量在用字符串常量初始化時,指針變量中存儲的是字符串的首地址,但字符串存儲在常量區。
    上面的文字描述有些晦澀,下面通過一段示例代碼來輔助理解,具體如下:

    存儲在棧區、堆區和靜態區上的數據是可更改的,存儲在常量區的數據只能在定義時賦值,且一旦賦值就不能再改變。
    (2)初始化及賦值方式
    初始化方式:可以對字符指針變量賦值,但不能對數組名賦值。
  • char str[(6] ="hello";//char str[6]; str="hello",這種寫法錯誤 char *p= "hello" //等價于char*p; p = "hello";

    賦值方式:使用數組定義的字符串只能通過為數組中的元素逐一賦值或通過調用復制函數的方式來賦值,而使用指針定義的字符串還可以實現直接賦值。

    char p1 = "hello", *p2;p2 = p1; char str1[6]="hello",str2[6];

    不可寫成str1=str2,不可數組賦值

    (3)字符指針與數組名字符指針變量的值是可以改變的,而數組名是一個指針常量,其值不可以改 變。
    (4)字符串中字符的引用:可以用下標法和地址法引用數組元素和字符串中的字符元素。

  • gets()函數與puts()函數
    (1)gets()函數讀入用戶輸入的字符串時,會讀取換行符之前所有的字符(不包括換行符本身),并在字符串的末尾添加一個空字符’\0’用來標記字符串的結束,讀取到的字符串會以指針形式返回。
    原型:char* gets(char* str)
    (2)puts()函數接收的參數是一個字符串指針,該指針指向要輸出的字符串,并且會自動在字符串末尾追加換行符"\n’。如果調用成功則返回一個int類型的整數,否則返回EOF
    原型:int puts(const char* str)
    ==puts()函數相比, printf()函數不會一次輸出一整行字符串,而是根據格式化字符串輸出一個個“單詞”。由于進行了額外的數據格式化工作, printf()函數比puts()函數效率稍低。然而print()函數可以直接輸出各種不同類型的數據,因此printf()函數比puts()函數應用更為廣泛。
  • 字符串連接函數
    在程序開發中,可能需要對兩個字符串進行連接,例如將電話號碼和相應的區號進行連接。就務調商
    為此, C語言提供了strcat)函數和strncat)函數來實現連接字符串的操作,這兩個函數的相關解具體如下:
    • strcat()函數
      strcat()函數的用法很簡單,它用來實現字符串的連接,即將一個字符串接到另一個字符串的后面。其函數原型如下所示:
      chat* strcat (char* dest, const char* src);
      表示將指針src指向的字符串接到指針dest指向的字符串之后。需要注意的是,在使用 strcat()函數之前, dest對應的字符數組必須要有足夠的空間來容納連接之后的字符串,否則會發生緩沖區溢出的問題
    • strncat()函數
      為了解決使用strcat()函數實現字符串連接時出現的“緩沖區溢出”問題,C語言提供了 strncat()函數。其函數原型如下:
      char* strncat (char* dest, const char* src, size_t n);
      strncat()函數除了接收兩個字符指針src和dest之外,還接收第三個參數n,該函數的功能是:獲取src所指字符串中的前n個字符,添加到dest所指字符串的結尾,覆蓋dest所指字串結尾的’\0’,實現字符串拼接。
  • 字符串復制函數
    strcpy()函數,該函數專門用于實現字符串的復制,其函數原型如下:
    char* strcpy (char* dest, const char* src);
    參數dest和src可以在字符串中的任意一個位置,字符串指針src所指向的字符串將被復制到dest所指向的字符串中。

  • 字符串比較函數
    (1)strcmp()函數:比較兩個字符串,其函數原型如下所示:
    int strcmp (const char* str1, const char* str2);
    (2)strncmp()函數:比較兩個字符串的前n個字符。其函數原型如下所示:
    int strncmp (const char* strl, const char* str2, size_t n);
    strncmp()函數指定比較前n個字符,如果 str1和str2的前n個字符相同,則函數返回值為0。

  • 選擇排序算法:是在每一趟排序過程中從待排序記錄中選擇出最大(小)的元素,將其依次放在數組的最前或最后端的排序方法。

  • 字符串查找函數
    (1) strchr()函數
    strchr()函數用來查找指定字符在指定字符串中第一次出現的位置,其函數原型如下所示;
    char* strchr (const char* str, char c);
    其中參數str為被查找的字符串, c是指定的字符。如果字符串str中包含字符c, strchr()函數將返回一個字符指針,該指針指向字符c第一次出現的位置;否則返回空指針。
    (2) strrchr()函數
    strrchr()函數用來查找指定字符在指定的字符串中最后一次出現的位置,其函數原型如所示:
    char* strrchr (const char* str, char c);
    其中參數str為被查找的字符串, c是指定的字符。如果字符串str中包含字符c,strrchr() 函數將返回一個字符指針,該指針指向字符c最后一次出現的位置,否則返回空指針。
    (3) strstr()函數
    上面兩個函數都只能搜索字符串中的單個字符,如果要在字符串中搜索是否包含一個子字符串時,可以使用strstr()函數,其函數原型如下所示:
    char *strstr (const char *haystack, const char *needle);
    其中參數haystack是被查找的字符串, needle是子字符串。如果在字符串haystack到了字符串needle,則返回子字符串的指針,否則返回空指針。

  • 字符串的其他常用函數
    (1)atoi()函數
    atoi()函數用于將一個數字字符串轉換為對應的十進制數,其函數原型如下所示.
    int atoi (const char* str);
    atoi()函數接收一個數字字符串作為參數,返回轉換后的十進制整數。如果轉換失敗,則返回0。需要注意的是, atoi()函數的聲明位于stdlib中
    (2)itoa()函數
    用來將一個整數轉換為不同進制下的字符串,其函數原型如下所示:
    char* itoa (int val, char* dst, int radix)
    第一個參數val表示的是待轉換的數,第二個素表示的是目標字符數組,第三個參數表示的是要轉換的進制。
    (3)sprintf()函數
    字符串格式化命令,主要功能是把格式化的數據寫入某個字符串中. sprintf()函數和printf()函數都是變參函數。其函數原型如下所示:
    int sprintf( char *buffer, const chat "Eormat, [ argument]…);
    第一個參數表示目標字符數組,第二個參數表示格式化字符串,第三個參數表示需要轉換的整數。

  • 編譯和預處理(…)

    結構體和共用體(…)

    文件

  • 計算機中的流
    在C語言中,將在不同的輸入/輸出等設備(鍵盤、內存、顯示器等)之間進行傳遞的數據抽象為“流”。例如,當在一段程序中調用scanf()函數時,會有數據經過鍵盤流入存儲器;當調用printf()函數時,會有數據從存儲器流向屏幕。流實際上就是一個字節序列,輸入函數的字節可被稱為輸出流。
    根據數據形式,輸入輸出流可以被細分為文本流(字符流)和二進制流。文本流和二進制流之間的主要差異是,在文本流中輸入輸出的數據是字符或字符串,可以被修改,而二進制流中輸入輸出的是一系列二進制的0、1代碼,不能以任何方式修改。

  • 文件
    (1)文件的概念
    文件是指存儲在外部介質上的數據的集合。一個文件需要有唯一確定的文件標識,以使用戶根據標識找到唯一確定的文件,方便用戶對文件的識別和引用。文件標識包含三個部分,分別為文件路徑、文件名主干、文件擴展名。

    操作系統以文件為單位,對數據進行管理,若想找到存放在外部介質上的數據,必須先按照文件名找到指路徑定的文件,再從文件中讀取數據。
    (2)文件的分類
    計算機中的文件分為兩類,一類為文本文件,另一類為二進制文件。
    文本文件又稱為ASCII文件,該文件中一個字符占用一個字節,存儲單元中存放單個字符對應的ASCI1碼。假設當前需要存儲一個整數數據21,則該數據在磁盤上存放的形式
    ’2‘(50)------->01010000
    ‘1’ (49) --------->00110001
    文本文件中的每個字符都要占用一個字節的存儲空間,并且在存儲時需要進行二進制和ASCIl碼之間的轉換,因此使用這種方式既消耗空間,又浪費時間。
    數據在內存中是以二進制形式存儲的,如果不加轉換地輸出到外存,則輸出文件就是一個二進制文件。二進制文件是存儲在內存的數據的映像,也稱為映像文件。若使用二進制文件存儲,則存儲空間更少且不需要進行轉換,如此既節省時間,又節省空間。但是這種存放方法不夠直觀,需要經過轉后才能看到存放的信息。

  • 文件的緩沖區
    目前C語言使用的文件系統分為緩沖文件系統(標準1/O )和非緩沖文件系統(系統I/O)ANSI C標準采用“緩沖文件系統”處理文件。
    聽謂緩沖文件系統是指系統自動在內存中為正在處理的文件劃分出了一部分內存作為區。當從磁盤讀入數據時,數據要先送到輸入文件緩沖區,然后再從緩沖區逐個把數據傳送序中的變量;當從內存向磁盤輸出數據時,必須先把數據裝入輸出文件緩沖區,裝滿之后,數據從緩沖區寫到磁盤。
    使用文件緩沖區可以減少磁盤的讀寫次數,提高讀寫效率。

  • 文件指針
    文件指針的定義格式如下:在C語言中,所有的文件操作都必須依靠指針來完成,因此在對文件進行操作之前,必須先使指針與文件建立聯系。
    FILE*變量名
    一個文件指針變量只能指向一個文件,也就是說,要操作多少個文件,就要定義同樣數量的文件指針

  • 文件的打開與關閉
    對文件進行讀寫之前,需要先打開文件;讀寫結束之后,則要及時關閉文件。
    (1)打開文件
    專門用于打開文件的函數fopen()函數,該函數的函數原型如下:
    FILE* fopen (char* filename, char* mode);
    其中返回值類型FILE*表示該函數返回值為文件指針類型;參數flename用于指定文件的絕對路徑,即用來確定文件包含路徑名、文件名主干和擴展名的唯一標識;參數mode用于指定文件的打開模式。
    文件正常打開時,函數返回指向該文件的文件指針;文件打開失敗時,函數返回NULL。

  • FILE* fp; fp.fopen ("D:\Itest.txt","); if (fp==NULL) {printf ("File open error!\n");exit (0); }

    一般在調用該函數之后,為了保證程序的健壯性,會進行一次判空操作。
    (2)關閉文件:類似于在堆上申請內存,文件在打開之后也需要一步對應操作,即關閉文件。
    關閉文件的目的是釋放緩沖區以及其他資源。若打開的文件不關閉,將會慢慢耗盡系統資源 C語言中專門用于關閉文件的函數fclose(), fclose()函數的函數原型如下:
    int fclose(FILE* fp)
    該聲明的返回值類型為int,如果成功關閉則返回0,否則返回EOF (“end of tile”,是文件結束的標識,包含在頭文件stdio.h中),函數中的參數fp表示待關閉的文件。

    (3)文件的打開模式

    打開模式名稱描述
    r/rb只讀模式以只讀的方式打開一個文本文件/二進制文件,如果文件不存在或無法找到 fopen()函數調用失敗,返回NULL
    w/wb只寫模式以只寫的方式創建一個文本文件/二進制文件,如果文件已存在,則創建新文件
    a/ab追加模式以只寫的方式打開一個文本文件/二進制文件,只允許在該文件末尾追加數據,如果文件不存在,則創建新文件
    r+/rb+讀取/更新模式以讀/寫的方式創建一個文本文件/二進制文件,如果文件不存在, fopen)函數調用失敗,返回NULL
    w+/wb+寫入/更新模式以讀/寫的方式創建一個文本文件/二進制文件,如果文件已存在,則重寫文件
    a+ab+追加/更新模式打開一個文本文件/二進制文件,允許進行讀取操作,但只允許在文件末尾添加數據,若文件不存在,則創建新文件

    6.寫文件
    文件分為文本文件和二進制文件,因為它們的存放形式不同,所以寫文件的方法也不一樣。
    (1)寫文本文件
    在對文本文件進行寫操作時,主要用到兩個函數,分別為: fputc()函數和fputs()函數。

    ① fputc()函數
    fputc()函數用于向文件中寫入一個字符,其函數原型如下:
    int fputc (char ch, FIIE *fp);
    其中ch表示寫入的內容,fp表示待寫入文件的指針, int表示返回值類型。

    ② fputs()函數
    使用fputs()函數可以向文件中寫入一個字符串(不自動寫入字符串結束標記符’\0’),成功寫入個字符后,文件位置指針會自動后移,函數返回值為非負整數,否則返回EOF。其函數原型如下:
    int fputs (const char* str, FILE file);
    其中參數str表示待寫入的一行字符串;參數file表示待寫入文件的指針; int表示返回值類型。
    (2)寫二進制文件
    對二進制文件寫操作主要使用fwrite()函數,原型為:
    unsigned Int fwrite (const void str, unsigned int size ,unsigned int count, FILE fil)
    參數str表示待寫寫入數據的指針;參數size表示待寫入數據的字節數;參數count表示待寫寫入數據個數;參數file表示待寫入數據的文件指針;返回值的類型unsigned int 為無符號整形。
    文本模式下具有特殊意義的字符(如‘\n’、’\0’),在二進制模式下沒有意義。
    (3) fprint ()函數
    除了從輸入設備寫入數據,還能從字符串中獲取數據,寫入文件中
    7. 讀文件
    (1)讀文本文件
    fgetc()函數:用于從文件中讀取一個字符
    ② fgets()函數:每次從文件中讀取一行字符串,或讀取指定長度的字符串。
    (2)讀二進制文件
    對二進制文件進行讀操作主要使用fread()函數, fread()函數用于在程序中以二進制的形式讀取文件,其函數原型如下:
    unsigned int fread (void dstBuf, unsigned int elementsize,unsigned int count, FILE* file);
    其中參數desBuf用于存儲待接收數據的指針;參數elementSize表示要接收的數據項的字節數;參數count表示每次函數運行時要讀取的數據項的個數;參數file為指向源文件的文件指針;返回值類型unsigned int表示函數返回值的類型為無符號整型。

    (3) fscanf()函數
    fscanf()函數用于從文件中格式化地讀取數據,其函數原型如下:
    int fscan (FILE* file, const char * format, .)
    其中參數file表示指向文件的指針,參數format表示文件中的字符串輸出時遵循的格式;返回值int表示函數返回值類型為整型。如果該函數調用成功,則返回輸入的參數的個數;否則返回EOF。
    舉例說明該函數的用法:
    Escant (Ip, “8sa”, work, age);
    因為數據只能從實參傳遞給形參,其中的參數應為指針變量,所以需要對整型變量age進行取址操作。
    7. 文件位置指針
    為了對讀寫進行控制,系統為每個文件設置了一個位置指針,用于指示文件當前讀寫的位置該指針被稱為文件位置指針。
    當從文件頭部開始,對文件進行順序讀寫時,文件位置指針伴隨著讀寫過程逐個后移,每讀寫一個數據,位置指針后移一個位置。下次讀寫開始時,系統會從文件位置指針指向的位置開始讀寫文件。
    文件位置指針也可以人為移動,實現文件的隨機讀寫。常用的控制文件位置指針的函數有三個;

  • seek)函數
    fseek()函數的作用是將文件位置指針移動到指定位置,其函數原型如下:
    int fseek (FILE* fp,long offset,int origin);
    其中參數tp表示指向文件的指針;參數offset表示以參數origin為基準使文件位置指針移動的偏移量;參數origin表示文件位置指針的起始位置,它有三個枚舉值:
    SEEK-SET:該參數對應的數值為0,表示從文件起始位置開始偏移。
    SEEKEND:該參數對應的數值為2,表示相對于文件末尾進行偏移。
    SEEK-CUR:該參數對應的數值為1,表示相對于文件位置指針當前所在位置進行偏移。
    在調用該函數時,若調用成功則會返回0,若有錯誤則會返回-1,該函數一般用于二進制文件,因為對文本文件進行操作時,需要進行字符轉換,對位置的計算可能會發生錯誤。
    (2) rewind()函數:可以將文件位置指針移動到文件的開頭,其函數原型如下:
    void rewind (FILE* fp);
    (3) ftell()函數:獲取文件位置指針當前指向的位置,其函數原型如下:
    long ftell (FILE* fр);
    == ftell()若調用成功,將返回文件位置指針當前所在的位量;若調用失敗,則返回-1。==
  • 總結

    以上是生活随笔為你收集整理的C语言程序设计案例式教程的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。