《C和指針》筆記

#include<stdio.h>的意思就是講預處理器用名叫stdio.h的庫函數頭文件的內容替換#include指令語句

這個整條語句叫做預處理指令  stdio.h才叫頭文件

C語言中數組參數是以引用(reference)形式進行傳遞的,也就是傳地址

1puts()函數和printf()函數輸出字符串的區別:

puts()函數,輸出一串字符串,並且會在末尾進行換行操作

使用printf()輸出字符串就不會進行換行

2、特殊字符表示:

三字母詞:幾個字符的序列,表示另外一個字符

例如:??(  表示一個[字符   ??)表示 ]

             ??<  表示一個{      ??>表示}

有的編譯環境也許會不處理三字母詞,vs2017就不處理

轉義字符:

如果在某個地方想要使用某個特定字符,但是這個字符在這裏有其他的意義,導致不可以使用該字符,這是就應該使用轉義字符,將特定字符作爲單個字符來處理,

\”   表示” 

\\   表示\

\r   表示回車

\t   表示製表符,一個製表符代表8個空格

\’   表示

\b  表示退格鍵(backspace

3#if  0

   .........

   #endif      也可以進行註釋代碼,功能要比/**/強大的多

4、註釋/**/裏面不可以有單獨的  */必須是成對出現的

5、長整形和整形以及短整形:

長整形並不一定比整形大,短整形也不一定比整形小

規定:長整形至少應該和整形一樣長,短整形最大和整形一樣大

Char 0------127

Sign char  -127----127

Unsigned char  0------255

Short int -32767------32767

int     -32767-------32767

Unsigned short int 0-------65535

Long int

 

6、枚舉類型:

enum{ cup,yellow ,blue,black

}name;

大括號中的單詞分別代表的是0 1 2 3

聲明爲枚舉類型的變量實際上是數類型, enum name; 你實際上可以給name賦值爲數字都可以

另外枚舉類型的變量的大小都是4字節

7、浮點類型:

       Double 類型至少和float類型一樣長

所有的浮點類型至少能夠容納從10^-3710^37之間的任何值

8、指針:

int *a;

變量名是a 類型是int*

int* a;int *a;

int* a,b,c; 寫成這樣很容易誤認爲b,c也是指針變量,實際上不是的

定義指針變量最好定義成 int  *a;

Char *pArr=張三;將字符串常量賦值給char*類型的指針變量pArr

9、typedef

     Typedef    char*  ptr_to_char;

ptr_to_char   a;  a是一個指向char類型的指針變量

使用typedef #define 的區別:

使用#define 重命名指針類型是無效的,typedef是可以的

例如:

#define    d_ptr_to_char  char*

Typedef char *ptr_to_char

聲明變量:

d_ptr_to_char   a,b; 這樣執行之後a被成功聲明成了指針類型的變量,但是b仍然是字符變量

ptr_to_char a,b;這樣執行之後a,b兩個 變量全是指針變量

 

10、常量:

   Const 聲明的常量樣子和變量一樣,只是他們的值是不允許修改的

常量的聲明:

int    const a;

const  int     a;  兩種方式是一樣的

那麼既然常量的值是不可以修改的,那麼就需要在聲明是直接初始化

或者作爲函數中形參的值,由實參進行賦值

指針和const 混合使用:

只需要記住const修飾的是其後面的變量,就像下面的例子:

int const *a;  也可以寫成 const int *a;    //因爲*a是被const修飾的,所以*a是一個常量,也就是說指針所指向的值是個常量

Int *const a;  不可以寫成const *int a;      //因爲a是被const修飾的,所以a是個常量,又因爲a是一個指針,所以指針是個常量

Int const *const a; //這種情況,因爲後面的const修飾的a,但是因爲a是一個指針,所以指針是個常量,又因爲前面的const修飾的是*a,所以*a是個常量,也就是指針所指向的值十個常量,所以這種用法是:指針和指針所指向的值都是常量


11、作用域:

四種不同類型的作用域:

1文件作用域

2函數作用域

3代碼塊作用域

4原型作用域

12、c語言內存四區:

內存四區模型:
操作系統給C/C++編寫的程序分配內存,通常將分配的內存劃分爲以下四個區域:
1.棧區:存放局部變量,用完由操作系統自動釋放
2.堆區:動態分配給程序的內存區域,由程序員手動釋放
3.數據區:
分爲兩種:
1)常量區:存放常量,一般是字符串常量
2)全局區/靜態區:存放全局變量和靜態變量
4.代碼區:
存放可執行代碼的區域

13:goto語句:

 

14getchar()返回的是int類型的值

 

15、逗號操作符:


16、指針:

每個計算機的內存有數以億計的位組成,每個位可以容納01,但是由於每個位所能表示的值的範圍太有限,所以由幾個位組成一個單位,來進行容納範圍更大的值

間接訪問操作符*

具有從右往左結合的結合性

指針的指針:

int   a  =  12;

int  *b  =  &a;

int  **c =   &b;

只要從右往左結合性一步步看就很好理解

A  相當於  12

b          &a

*b         a,12  

C          &b

*c         *b, b,&a

**c        *b , a,12

指針的類型:去掉變量名剩下的就是指針的類型 int*

指針指向的類型: 去掉變量名和*剩下的就是   int

*的運算級別高於+的運算級別,但是小於++的運算級別

char str[10] = "ABCDE";

char *p = str;

               單獨執行下面的一個語句:

printf("*p=%c\n",*p);       結果是A

printf("*p++=%c\n",*p++);   結果也是A

printf("*++p=%c\n", *++p);   B     

printf("++*p=%c\n", ++*p);   B  

需要注意的是++p得到的是p後面的那一個數的地址,不是僅僅只用p的地址加1,而是p的地址加上 類型所佔的字節數*1

也就是說++p   《===》   p+(sizeof(int)*1)

如果p的地址是      10011

那麼++p的地址就是   10015

17、 如何在函數中使用可變參數?

頭文件stdarg.h   va_list類型的變量 訪問可變參數

                 Va_startva_arg   va_end

 

18、 數組

int b[10] ,b[0]int類型的  b是什麼類型呢?因爲數組名錶示數組的地址,所以在這裏b就是指向int類型的指針常量,注意不是指針變量,所以你無法修改b的值,因爲數組的地址是一定的,因此數組名的值是一個指針常量

所以不可以使用a++。必須使用a+1

int a[10];

Int *b=a;int *b=&a[0],有區別嗎?

回答:因爲數組名錶示的就是數組的首個元素的地址,所以上面的兩條賦值語句是完全一樣的

除了優先級之外,下標引用和間接訪問是完全一樣的

數組中看着很奇怪但是是正確的語句:

5[a]     是和    a[5]  完全一樣的

因爲a[5]  如果使用間接訪問訪問的寫法就是  *a+5)那麼和 *(5+a)不是一樣的嘛

所以也是可以寫成  5[a] 是完全沒有問題的

指針與下標的運行效率比較:

多維數組數組名錶示含義:

Int a[5][10];

數組名a可以看做是一個一維數組,它包含五個元素,只是每個元素又包含十個整形元素

因爲a是指向數組的第一個元素,也就是數組首元素的地址,所以a是一個指向一個包含十個整形元素的數組的指針,簡單說a就是數組指針

例如int a[3][5]

數組名a指向第一行   是數組指針

a+1指向第二行

a+2 指向第三行

*a表示 a[0]這個指向5個元素的一維數組   是數組

*(a+1) 表示 a[1]  是個數組

*(a+2) 表示 a[2]  是個數組

使用間接訪問表示a[2][4]這個元素 *(*(a+2)+4)

其他語言允許寫成a[3,5]

但是在C語言中標a[3,5]僅僅是表示a[5] ,如果沒有越界的話還好

指向數組的指針:

例如

int a[5], *p=a;

int a[3][5], *p=a;

第一行語句是合法的,p是一個指向一維數組的指針

但是第二句就是非法的,因爲 a本身就是一個指向數組的指針,將一個數組指針賦給一個指針,是不可以的 除非p也是一個數組指針  可以這樣寫 int (*p)[5] =a; 下標的優先級高於間接訪問所以要加括號    

作爲函數參數的多維數組;

Int a[5];

Fun(a);

這樣的一維數組 函數原型可以是一下這樣的

Void funint a[]

       或者 void fun(int * a)   因爲一維數組名只是首元素的地址,所以形參使用一個指針變量即可

那麼對於這樣的二維數組呢?

Int a[3][5];

Fun(a);

函數原型可以是一下兩種:

 Void fun(int a[][5])

或者 void fun(int (*p)[5])  

這是因爲二維數組名,表示的是一個數組指針,所以形參必須也是數組指針

那麼爲什麼需要第二個數字5,而不是第一個數字3呢?因爲編譯器必須知道第二個及以後各維的長度,才能對各下標進行求值

對於多維數組如何初始化:

   二維數組:

int b[3][5] =

{

    {1,2,3,4,5},

    {1,1,1,1,1},

    {1,1,1,1,1},

};

   三維數組:

int a[2][3][4] =

{

    {

        {1,1,1,1},

        {1,1,1,1},

        {1,1,1,1},

    },

    {

        {2,2,2,2},

        {3,3,3,3},

        {4,4,4,4},

    },

};

四維數組:

對於多維數組初始化時從前面的中括號往後面看的

數組指針:

          表示是一個指針,指向的是一個數組的地址

     int (*p)[5]

指針數組:

  表示是一個數組,只是數組的元素存放的是地址

除了類型之外,指針變量和普通變量很相似,只是普通變量是存放的數字,指針變量是存放的變量的地址罷了,

那麼有數組,當然也可以有指針數組,數組元素中是存放的地址罷了

int * p[10];  p是一個int* 類型的指針數組,可以存放十個整形變量的地址

一維數組名取地址表示什麼?

int a[5];

&a和a 和&a[0] 的值都是一樣的,但是&a的類型是 int (*)[5] 是一個數組指針

a+1表示 數組的首地址加上 1*sizeof(int)

然而 &a+1表示 數組的首地址加上 1*sizeof(a) ,也就是加上的一個數組的佔的所有的字節長度

 

int a[4][5]; 假設數組的首地址爲1000的話

那麼  a=1000

A+1=1020

A[1]=1020

*(a+1) =1020

A[1]-1=1016

指針函數與函數指針:

返回值是某一種指針的函數叫做指針函數

指針指向函數的地址叫做函數指針、

函數指針除了將函數名用函數指針代替,其他和函數一樣

函數指針的定義和初始化:和函數原型一樣

Int min(int x,iny y);  函數原型

Int (*p) (int x,int y);

函數指針:

 

字符串:

要注意strlen()函數返回的是無符號整形類型的值

第十章:結構和聯合:

數組是相同元素的集合

結構也是一些值的集合,這些值稱爲他的成員

結構的聲明:

Struct  tag

{

member-list

} variable-list;  

下標引用和點操作符的優先級是一樣的,他們的結合性都是從左往右

->優先級高於*也高於 &

++高於*  但是+小於*

動態申請內存:

Malloc() 成功返回的是void*類型的指針,失敗返回NULL(相當於0

申請的是一塊連續的內存

Int *p=malloc(25*sizeof(int));   //申請100字節的內存(假設int類型佔4個字節)

初始化:

forint i=0;i<25;i++

 *p++=0;

或者

for(int i=0;i<25;i++)

  P[i]=0;

Free() 釋放內存函數,必須是釋放一整塊,不能是一部分

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