C語言學習之——數組與指針

最近看C相關的代碼,總是很吃力,所以決定看看C Primer Plus這本書,這裏對指針,字符串這些常用的部分做一個筆記

sizeof,指針,數組

  • 看代碼:
//sum_arr1.c --數組元素之和
#include<stdio.h>
#define size 10
int sum(int ar[], int n);
int main(void)
{
    int marbles[size] = { 20, 10, 5, 1, 22, 18, 18,123, 123,12 };
    long answer;

    answer = sum(marbles,size);
    printf("the totole number of marbles is %ld.\n",answer);
    printf("the size of marbles is %ld.\n", sizeof marbles);
    return 0;
}
int sum(int ar[], int n)
{
    int i;
    int total = 0;

    for(i = 0; i < n; i++)
        total += ar[i];
    printf("the size of ar is %ld.\n", sizeof ar);
    return total;
}

  • 在這裏插入圖片描述
  • sizeof是以字節爲單位,所以10個int的數組的size是40
  • ar長是8,說明指針地址長度是8個字節,即48位,這個計算機有關
  • sizeof 數組 和 sizeof指針的區別
  • 指針+1 ,指的是+1個存儲單位,對於marbles數組來說是4個字節,即指針+1,地址大小+4
  • 對於c,ar[i]*(ar+i)這兩個表達式等價。無論ar是數組名還是指針變量,這個兩個表達式都沒有問題;然而只有當ar是指針變量,才能用ar++這種表達式。

指針操作

  • demo
//ptr_ops.c -- 指針操作
#include<stdio.h>
int main(void)
{
    int urn[5] = { 100, 200, 300, 400, 500};
    int *ptr1, *ptr2, ptr3;

    ptr1 = urn;           //把一個地址賦給指針
    ptr2 = urn[2];

    printf("pointer value , dereference pointer, pointer address:\n");
    printf("ptr1 = %p, *ptr1 = %d, &ptr1 = %p\n", ptr1, *ptr1, &ptr1);

    //指針加法
    ptr3 = ptr1 + 4;
    printf("\n adding an int to a pointer:\n");
    printf("ptr1 + 4 = %p, *(ptr1 + 4) = %d", ptr1 + 4, *(ptr1 + 4));
    //遞增指針
    ptr1++;
    printf("\n value after ptr1++ \n");
    printf("ptr1 = %p, *ptr1 = %d, &ptr1 = %p\n", ptr1, *ptr1, &ptr1);
    //遞減指針
    ptr2--;
    printf("\n value after ptr2-- \n");
    printf("ptr2 = %p, *ptr2 = %d, &ptr2 = %p\n", ptr2, *ptr2, &ptr2);
    --ptr1;//恢復指針
    --ptr2;
    printf("\n pointers reset to original values\n");
    printf("ptr1 = %p, ptr2 = %p\n", ptr1, ptr2 );
}

  • 在這裏插入圖片描述
  • 注意:
	double *pd;
	*pd = 2.4
  • 這樣用錯誤,因爲創建一個指針,未初始化時,系統只分配了儲存指針本身的內存,並未分配儲存數據的內存,即指針的值,因此,在使用指針之前,必須先用已分配的地址初始化它;而此處第二行的意思時把2.4存在pd指向的位置,但是pd未初始化,所以不知道存在哪裏

關於const

對形參使用const:

int sum(const int ar[]);

const是爲了告訴編譯器,不能修改ar指向的數組中的內容,如果修改了,會編譯器會捕獲並拋出錯誤。這是爲了讓我們在給函數傳參時保護數組數據不被改變。

void show_array(const double ar[], int n);
void mult_array(double ar[], int n)

如上面的聲明,只是顯示數組,那麼不需要改變,傳參加const;但是修改數組,需要改變,則不加;

const與指針賦值

  • 把const或非const數據的地址賦值給指向const的指針是合法的:
double rates[5] = {88.99 , 110.2, 123.1, 200.4, 210};
const double locked[4]={0.1, 0.2, 0.5, 0.9};
const double *pc = rates; //有效
pc = locked; //有效
pc = &rates[3];//有效
  • 然而,只能把非const數據的地址賦值給普通的指針,
double *pnc = locked; //無效

因爲,如果可以的話,那麼普通指針可以改變const數組的數據了。

  • 也不要把const數組當作實參傳遞給mult_array這樣的函數
mult_array(rates,5);//有效
mult_array(locked,5);//不可以

因爲使用形參修改const數據的後果未知

  • 注意 * const pc
double * const pc = rates; //指向數組開始
pc = &rates[3]; //不可,const指針不可改變指向
*pc = 12.1; //可以,可以更改const指針指向的值;

數組和多重指針

  • 看一個例子:
/*zippo1.c -- 指針和多維數組*/
#include<stdio.h>
int main(void)
{
    int zippo[4][2] = { { 2, 4 }, {6,8},{1,3},{2,0}};

    printf(" zippo = %p,    zippo + 1 = %p\n", zippo, zippo + 1);//zippo是兩int組成的一維數組的地址,所以+1,相當於地址+8
    printf(" zippo[0] = %p,    zippo[0] + 1 = %p\n", zippo[0], zippo[0] + 1);//zippo[0] 是一個int的地址,所以+1,即地址+4, 你可以類比一維數組char ar[2];ar是一個char的地址,char[0]纔是該地址的值,所以zippo[0]是兩個Int組成的一維數
組的地址,那麼zippo就是這個地址的地址
    printf(" *zippo = %p,    *zippo + 1 = %p\n", *zippo, *zippo + 1);//zippo的解引用應該是zippo[0]的地址,+1應該是地址+8
    printf("zippo[0][0]=%d\n", zippo[0][0]);
    printf("  *zippo[0]=%d\n", *zippo[0]);// *zippo[0]指的是zippo[0]指向的一int的解引用,那麼還是首地址對應的一個int
    printf("  **zippo = %d\n", **zippo);// zippo是地址的地址,所以必須解引用
兩次才能獲得原始值,即zippo[0][0]
    printf("  zippo[2][1] = %d\n", zippo[2][1]);
    printf("*(*(zippo+2)+1) = %d\n",*(*(zippo+2)+1) );

    return 0;


}
  • 在這裏插入圖片描述
  • 二維數組zippo的地址和一維數組zippo[0]的地址相同,他們的地址都是各自數組首元素的地址,因而與&zippo[0][0]也相同
  • zippo[0]指向一個四字節的Int,所以+1,地址+4;zippo是一個內含2個int類型值的數組的地址,所以指向一個8字節的數據對象,所以+1,地址+8(相當於zippo是一個儲存單位是8字節的一維數組)
  • zippo[0]與*zippo完全相同。對二維數組名解引用兩次,得到儲存在數組中的值,和數組使用兩個[][]得到數組中的值對應
  • 所以zippo[2][1]與 *(*(zippo+2)+1) 是對應的,所以說用數組更直觀
  • 考慮int (*pz) [2]:pz是一個指向內含兩個int類型的數組。其實不用想太複雜,知道pz的儲存單位是8個字節,*解引用與[]等價即可:
pz+1 即地址+8
pz[0] + 1 ,pz解一層引用即成爲了指向int的地址,+1,即+4
*pz + 1同理
pz[0][0]*pz[0] **pz表示的都是首地址數據
pz[2][1]*(*(pz+2)+1)等價
  • 多維數組的函數聲明

    int sum(int ar[][4]) //正確
    int sum(int ar[][])//不可
    int sum(int ar[3][4])//3會被忽略
    
    • 這樣可以傳入變長數組,第一個[]內可是1,2.。。
  • 複合字面量:

int sum(const int ar[])
...
int total3;
total3 = sum((int []){1,2,3,4,5,6});
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章