程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 淺談C的應用與常見error

淺談C的應用與常見error

編輯:關於C語言

淺談C的應用與常見error


我下面所寫的都是用“.c”後綴的。“.c”後綴是c源文件的後綴,“.cpp”後綴是c++源文件的後綴。c++繼承了c語言的一些特性,所以有些bug在“.cpp”裡是可以通過的。         1、scanf()你真的了解了麼?;       scanf()是有返回值的,返回值類型是int,這個你知道麼?它返回了成功讀入輸入信息的個數。       那麼我們可以利用它來做什麼呢?       非零即真,這句話你一定聽說過,而且不止一次。那麼我們看一下下面的代碼。         int a;        while (scanf("%d", &a) == 0)        {             printf("請輸入合法字符:");        }       這樣寫代碼是不是好一點,再輸入的同時判斷了輸入的是否正確。但這會使你進入一個死循環。為什麼會這樣呢?         我們在輸入時,我們的鍵值需要一塊緩沖區在存放鍵值,如果輸入的鍵值不被scanf()接受,那麼它會一直在緩沖區中,那麼再仔細看一看上面的代碼,你是不是明白了呢。       解決這個問題並不難,只要將輸入的鍵值接受,他就不會在緩沖區中影響你的程序了。看看下面的代碼,有沒有豁然開朗,哇,scanf()還可以這麼使用!        int a;        while (scanf("%d", &a) == 0)        {             getchar();             printf("請輸入合法字符:");        }           2、你還在糾結while(),for();       初學者可能會糾結什麼場合用while(),什麼場合用for()。       在我看來,這根本不存不值得我去糾結,我們應該想的是使用哪個可以使程序更簡單,別人更容易看懂。       while(),for()的本質都是循環,只是形式不一樣而已。       int i = 0;            int i;       while (i<10)           for (i=0; i<10; i++)       {                {         i++;       }                }       上面的代碼當然是for()更簡明一寫,但1、中的例子卻是使用while()。for()比while()在語句要多一些,這是你需要的麼?       根據每個人的代碼風格不同,不能統一要求使用for()或者while()。建議初學者可以兩個都試一下,感覺他們之間的不同,寫出漂亮的代碼。         3、switch()你會使用麼?       switch(n)       {       case 1:         break;       case 2:         break;       default:       }       你一直這麼使用麼?       我們都知道case 後面不加break,會一直執行下面的代碼,直到代碼全不執行完或者遇到break。       利用這個特性,我們是不是可以做一些其他的事,比如加法,一年有十二個月,我想算出4月6號是今年的第幾天,你想到怎麼使用了麼?我們看一下下面的代碼。       switch (month-1)        {     case 11: sumMonth += 30;     case 10: sumMonth += 31;     case 9: sumMonth += 30;     case 8: sumMonth += 31;     case 7: sumMonth += 31;     case 6: sumMonth += 30;     case 5: sumMonth += 31;     case 4: sumMonth += 30;     case 3: sumMonth += 31;     case 2:            if ((i%4==0 && i%100!=0) || i%400==0)             {                    sumMonth += 29;            }             else             {                sumMonth += 28;             }       case 1: sumMonth += 31;     }       你看懂了麼?只是提供一個思路,將我們思維打開,你會看見另一片天空。       你在case中定義過變量麼?       case中為什麼不能定義變量呢?          int a;        switch (a)       {       case 1:           int b;           break;       case 2:           b = 0;           break;       }     你這麼任性,編譯器怎麼辦!       那我們為什麼不規定case 1定義的變量只能在case 1中使用呢?在6、變量作用域中你將會找到答案。       當然,我們不應該只局限於switch(),if() else也一樣可以完成多重選擇的任務,不過switch()內置3-999個標簽,使用switch()的程序運行速度可能稍快一些,代碼也更簡潔。          4、if()的使用       我們都知道if()用於判斷。那麼當你判斷兩個字符相等時,你會怎麼寫?       int a;        if (a == 5)       如果是我,我會寫成       int a;        if (5 == a)       功能是一樣的,何必這麼麻煩?我們在做一個項目時,不可能十行代碼調試半個小時,當我們思維在鍵盤上飛舞時,我才體會到一個程序員的快樂。在我們正在體驗這種快樂時,手誤在所難免,如果寫成if(a=5),這個錯誤夠你找兩天的。但是if(5=a),編譯器就可以幫你找到。       當你想判斷兩個字符串是否相等時,你會不會這樣寫?       char c_c1[10] = "acdefg";       char c_c2[10] = "qwerty";       if (c_c1 == c_c2)或者if (c_c1[10] == c_c2[10])       總之都是不對的。字符串,數組,指針後面還會有所涉及,這裡不做詳談。       比較兩個字符串我們用到了C函數庫中提供的strcmp()函數,它包含在<string.h>頭文件中。strcmp()返回了一個int類型的值,-1,0,1。0代表兩個字符串相等,-1,1是由於字符之間的比較(ASCII)決定的。下面我看一個例子。       char c_ch[10] = "qwertyui"  //最多可以存放9個字符,最後一位是”\0“       char *p_ch = "adfgf"       strcmp(c_ch, p_ch);  //strcmp()中的兩個參數是兩個字符串的地址       strcmp("qwertyui", "adfgf");  //這樣也是可以的,字符串存放的也是首字母的地址,後面會提到。            5、你知道頭文件的作用麼?     我們寫代碼都習慣把#include <stdio.h>最先寫上,但你知道它的作用麼?     #include :文件包含     當預處理器發現#include 指令後,就會尋找 <>中的文件名並把這個文件包含到你寫的程序代碼,替換源文件(就是你寫的文件)中的#include。雖然你只寫了一行代碼,但是編譯器卻給你添加了很多代碼。     <stido.h>包含了輸入輸出函數,所以在程序的調試階段,他是不可少的。     #include "gaozy" 這類頭文件你見過麼?它與#include <stdio.h>又有哪些區別呢?<>包含的頭文件,編譯器會在系統目錄中搜索。“”包含的頭文件,編譯器會先在當前工作目錄中搜索,如果沒有,再去系統目錄中搜索。也可以簡單的理解成C函數庫裡的函數在<>包含的頭文件裡,而我們自己寫的函數則放在“”文件中。         6、變量作用域     int i;     while (1)     {       int i = 0;       printf("%d", i);     }     這樣會報錯麼?當然不會,因為兩個int i;並不在同一個作用域。     那麼什麼是作用域,怎麼分辨作用域呢?     我們通常把一個{}內的代碼看成在一個作用域。這也是為什麼case裡不可以定義變量的原因。     只有{}才可以分辨作用域麼?     當然不是     while (1)       int i;     printf("hellow world!");     int i;自己單獨在一個作用域中,printf()只會執行一次,當然這是一個死循環,不會執行到printf()。現在你有點略懂了麼?跟while()相同的還有for(),if()     還有個問題你想過麼?第一次循環定義一個 i,第二次循環又定義一個 i,這不重復定義了麼?     當然不是,作用域內的變量是有生命周期的。也就是說,當第一次循環結束,你所定義的 i 的內存空間已經被釋放。          7、傷腦筋的bug     你寫過這樣的程序麼?     int i;     while (1)     {       int i = 0;       printf("%d", i);       int j;     }     編譯器是這樣報錯的::\c\淺談c.c(49) : error C2143: syntax error : missing ';' before 'type'     我英文不好,不理解這句話是什麼意思,但是這段代碼裡根本不存在缺少;的情況。     我將代碼粘到vs2010中,它是可以運行的。我一度懷疑是編譯器出錯了。但事實上編譯器是很少出錯的,糾結了很久,我突然想起來,c語言中規定,變量是必須在作用域的開始定義。vs210中,我用文件是後綴是.cpp的,就是是說c++允許在其他函數之後定義變量,而c對此則表示不支持。         你寫的代碼有沒有之前運行正常,你只是修改了一點,語法上別沒有出錯。但編譯器卻報錯了呢?     LINK : fatal error LNK1168: cannot open Debug/SMIS.exe for writing     之前遇見這個問題也是糾結很久,為什麼一會兒可以編譯,一會兒又讓我等待呢?     這也不是編譯器出錯了。而是你執行了程序,沒有關閉,對代碼進行了修改,又要執行程序。     編譯器如果會說話:“小子,你拿我開心呢吧,還能不能一起玩耍了。”         當你malloc時,要記得free啊,還有malloc之後跟上一個判斷是有必要的。     p_head = (P_STUDENT)malloc(sizeof(STUDENT));      if (NULL == p_head)      {          printf("動態內存分配失敗,程序結束!");          exit(-1);      }     如果沒有if()判斷的話,在內存分配失敗時,運行程序會出錯,而且很難找到錯誤原因。         8、字符串,數組,指針     談到字符串、數組、指針,那麼我們就不得不談內存了。我們可以把內存理解成一排很長很長的房子,它是一個線性結構。房子裡住著不同的人家,每個房子有不同編號。   人家對應的是計算機裡定義的變量,房子編號對應的是變量所在地址。所以,我們每定義一個變量,都會占用一套房子,當房子被全部占用時,你的電腦就崩潰了。當然,我們電腦的內存還是很大的。下面來看看字符串、數組、指針之間的關系。     字符串以“/0”結束,所以字符串長度要在實際長度上+1     數組名就是數組首元素的地址     char ch[10] = "asdfg";  //ch[10]是定長數組     char ch[] = "asdfg";  //ch[]沒有規定長度,但是在定義時必須初始化     char *p_ch = "asdfg";  //指針指向字符串的首地址     這三種定義字符串的方法差不多。ch和p_ch都是地址。     數組定義之後不可改變,指針還可以指向其他地址,但要注意內存洩露。          9、指針與地址     有些書上說指針就是地址,其實這種說法並不准確。     那麼指針是什麼,地址又是什麼?     首先地址就是地址,物理內存的編號。     指針是一個變量,這個變量存放的內容是內存的物理地址。就像int i; i 是一個變量,存放一個 i 值。指針變量也存放一個指針值,這個值是一塊物理內存的地址。     其實指針是地址還是變量並不影響我們對指針的使用。         10、你用過宏麼?     #define MAX 60     就是MAX = 60;的意思,之後的代碼中MAX都等於60。宏使我們的程序維護更簡單,也更容易理解。         11、malloc與free     有人說new跟delete更強大,但我並這麼認為,new和delete是c++中的運算符,提供了對對象的操作。而malloc和free是c語言中用來進行動態內存分配的,不具備可比性。 C語言是面向過程的程序設計,根本沒有對象的概念。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved