C語言基礎(一)

參看: 《C程序設計語言》第二版

上面的參考書籍是主要的學習手段,下面只是針對一些特定的問題進行論述,這些特定的問題,書中可能沒有提到。

一個對象的類型決定着該對象可取值的集合以及可以對該對象施行的運算。


問題1:我們知道基本的數據類型有四種char,int,float,double。 類型修飾符也有四種short, long, signed, unsigned。 類型修飾符和基本數據類型的組合並不是都是有效的,其中修飾符是可以並存的,前提是這種表示是有意義的,比如”unsigned long int”,還有,修飾符或者基本類型定義的順序是無關的,比如“unsigned long int”和“long int unsigned ”是等同的,這些組合詳細可以參考《C程序設計語言》第二版的第二章。現在的問題是char類型能否表示所有的標準的ASCII碼錶的值?

答:基本的數據類型都有默認的類型修飾符,但是到底是哪個類型修飾符是依賴機器的,char類型就是個例子。signed char的取值範圍是-128~127, unsigned char 的取值範圍是0~255。標準的ASCII碼錶只使用了7位,它的取值範圍是0~127。從上面的分析可以得知char類型能表示所有的ASCII碼標的值。

補充:const的修飾符是後來加上的,對於這個修飾符我們也會有一個問題。


問題2:指針類型的變量定義不同於基本類型變量的定義。基本類型變量的定義基於兩部分,前半部分是基本類型、類型修飾符和存儲類型(auto,static等 ,後面關於這個還有幾個問題),第二部分是變量名。指針類型變量的定義是分爲三個部分,第一部分和基本類型變量的定義的前半部分是相同的,第二部分是符號”“,第三部分是變量名。比如,我們定義一個整型指針類型的變量”int p;”。我們的問題是const char * p; char const * p; char * const p; 三個表示方式有什麼差別?

答:要解決這個問題,我們需要清楚三件事情,基本類型的前半部分是否有順序的問題?第二件事情是修飾符語義的表達範圍?第三件事情 、*p 和 p 有什麼區別?
基本類型的前半部分是不依賴順序的,但是我們有一些編寫習慣的問題,比如我們往往只會寫”const int a;”,而不是“int const a;” 。
修飾符的語義表達範圍涉及到剛剛我們定義的三部分,修飾符只能修飾之後的部分,比如說,如果const 在第一部分,那麼const能修飾第二部分和第三部分,如果const 在第二部分和第三部分之間,那麼const只能修飾第三部分。
*p和p是有區別的。 “*”是表示間接引用運算符,它不是類型修飾符,所以我把它放在了第二部分,嚴格意義上來說,第二部分和第三部分是不能有任何其他的修飾符的,但是後來出現了const,const的語義是用來保證變量空間值的不可更改性。*p和p代表的不同的意思,*p代指間接引用空間,p本身代表指針變量的空間。
從上面的論述我們很容易得出下面的三個結論:
1. const char *p 和 char const * p是等價的。
2. const char *p 表示const修飾 *p空間,所以意思是*p空間的值不能被修改。
3. char * const p表示const修飾p空間,所以意思是p空間的值不能被修改。

驗證const char *p;

/*************************************************************************
    > File Name: main.c
    > Author: mhsheng
    > Mail:[email protected] 
    > Created Time: Wed 16 Nov 2016 06:07:52 PM CST
 ************************************************************************/

#include <stdio.h>
#include <stdlib.h>

int
main(int argc, char **argv)
{
    char c[]    = "abcde";
    const char * pc = c;

    c[0]    = 'y';
    pc[0]   = 'x';

    exit(0);
}
針對上面的代碼,如果使用gcc main.c我們會得到如下的錯誤:
main.c: In functionmain’:
main.c:18:2: error: assignment of read-only location ‘*pc’
  pc[0] = 'x';
  ^

驗證char * const p;

/*************************************************************************
    > File Name: main.c
    > Author: mhsheng
    > Mail:[email protected] 
    > Created Time: Wed 16 Nov 2016 06:07:52 PM CST
 ************************************************************************/

#include <stdio.h>
#include <stdlib.h>

int
main(int argc, char **argv)
{
    char        c[] = "abcde";
    char        d[] = "abcde";
    char * const    pc  = c;

    pc = d;

    exit(0);
}
針對上面的代碼,如果使用gcc main.c我們會得到如下的錯誤:
main.c: In functionmain’:
main.c:18:2: error: assignment of read-only variable ‘pc’
  pc = d;
  ^

問題3: const在C語言中有什麼用處?

答:const是後來才加入C語言標準中的,從某個方面來說它是後媽生的孩子,因爲是後媽生的,所以這個孩子會很調皮(簡單地說就是它的使用語義場景並不是都是定義好的),對於調皮的孩子我們的處理方式是,只關心一些正常的CASE使用,不關心一些開發中不會用到的場景,比如說我想把一個const指針強制轉換成一個非const的指針,我認爲這是非法使用,const嚴格意義上說不是變量修飾符,它是用來限定不同通過該變量來修改變量所指向的內存空間的值
在C語言中,有三種用法:
1. 修飾變量。
2.修飾函數參數。
3.修飾函數返回值。
在C++語言中,多了一種用法:
4.修飾成員函數,限定在成員函數中不可修改非靜態成員變量的值。

依據我剛纔對const的語義的理解,const修飾的int變量,不能作爲數組的常量表達式。比如:

const int LEN = 10;
int a[LEN] = {0};

個人認爲這是非法的,但是在C++中,這種行爲確實是可行的,雖然C++上說了這種方式的N種好處,但是個人還是不推薦使用,從某種意義上來說LEN就是一個常量,但是依據我對const的理解,LEN其實還是一個變量,而數組的定義是需要常量表達式的,所以個人認爲這是不科學的。產生這種分歧的根本原因是,const是後媽生的。


問題4:類型轉換的規則是個非常複雜的過程,主要的原因是變量類型的所能表示的值集合空間是不一樣的,有些值集合事有包含關係,可是有些集合只是有交叉。那麼爲什麼會有類型轉換的需求呢?

答:C語言中的多目操作符要求操作的對象類型必須保持一致,這樣操作符產生的結果纔會確定下來。簡單的說爲了防止二義性。如果沒有類型轉換,我們就無法知道一個整型數和一個浮點型想加,最終的結果是一個浮點型的還是一個整型的?
我們的轉換使用從小的集合轉到大的集合,從有符號轉到無符號,從整型轉到浮點型。這就是基本的轉換方式,但是具體到特定情況,就會變得很複雜,如果是負值從小的類型轉換到大的類型,高位是採用“符號擴展”,還是採用“0值填充”呢?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章