&運算符
指針是 c 語言最重要的概念之一,用於存儲變量的地址。&運算符給出變量的存儲地址,可以把地址看作變量在內存中的位置。
指針
指針是一個值爲內存地址的變量(或數據對象),指針變量的值是地址。
ptr = &pooh; //把 pooh 的地址賦給 ptr,可以說 “ptr 指向 pooh”
*間接運算符
後跟指針表示給出儲存在指針指向地址上的值,也可直接跟地址。
聲明指針
- 聲明指針變量時必須指定指針所指向變量的類型,不同的變量類型佔用不同的存儲空間
int * pi; // “ * ” 表示聲明的變量是指針
//語句含義:pi 是一個指針,*pi 是 int 類型
//pi 是什麼類型?描述的類型是“指向 int 類型的指針”
//pi 的值是一個地址,由無符號整數表示,不要認爲是整數類型,所以指針實際上是一個新類型。
//通常聲明時 * 後加空格,在引用變量時省略空格
- 指針運用,解決函數間通信問題,代碼示例
#include<stdio.h>
void swap(int* u, int* v);
int main(void)
{
int x = 5;
int y = 10;
printf("Originally x = %d and y = %d\n", x, y);
swap(&x, &y); //傳遞的是地址,不是值
printf("Now x = %d and y = %d\n", x, y);
return 0;
}
void swap(int* u, int* v) //u,v 是指向整數的指針
{
int temp;
temp = *u; //取地址上的值
*u = *v;
*v = temp;
}
- 運行結果
指針與數組
數組表示法其實是變相地址使用指針
- 重點
- 數組名是數組首元素的地址,如果 flizny 是一個數組,下面的語句成立:
flizny == &flizny[0];
- C 語言中,指針 “+1”指的是增加一個存儲單元。數組中,加1後的地址是下一個元素的地址,而不是下一個字節的地址,也就是遞增它所指向類型的大小。這也是爲什麼必須聲明指針所指向對象類型原因之一。
- C 語言標準在描述數組表示法時藉助了指針,定義 arr[n] 的意思是 *(arr + n)。可以認爲是“到內存的 arr 位置,然後移動 n 個單元,檢索在那裏的值。”
dates + 2 == &dates[2] //相同的地址
*(dates + 2) == dates[2] //相同的值
- 只有在函數原型或函數定義頭中,纔可以用 int ar[] 代替 int* ar,都表示 ar 是指向 int 類型的指針。
int sum(int* ar, int n); //等價於下面
int sum1(int ar[], int n);
- 代碼示例
#include<stdio.h>
#define SIZE 4
#define MONTHS 12
int sum(int* ar, int n);
int sum1(int ar[], int n);
int sump(int* start, int* end);
int main(void)
{
short* pi;
short array[SIZE];
int index;
int answer, answer1,answer2;
int days[MONTHS] = {31,28,31,30,31,30,31,31,30,31,30,31};
pi = array; //把數組地址賦給指針,也就是首元素地址
for (index = 0; index < SIZE; index++)
printf("pointers + %d: %10p\n", index, pi + index);
for (index = 0; index < MONTHS; index++)
{
printf("Month %2d has %d days.\n", index + 1,
*(days + index)); //與 days[index] 值相同
}
answer = sum(days, MONTHS);
answer1 = sum1(days, MONTHS);
answer2 = sump(days, days + MONTHS);
printf("The size of days is %zd bytes.\n", sizeof days);
printf("The total number of days is %ld.\n", answer);
printf("The total number of days is %ld.\n", answer1);
printf("The total number of days is %ld.\n", answer2);
return 0;
}
int sum(int* ar, int n)
{
int total = 0;
for (int i = 0; i < n; i++)
total += ar[i]; //ar[i] 與 *(ar + i) 相同
return total;
}
int sum1(int ar[], int n) //數組表示法
{
int total = 0;
for (int i = 0; i < n; i++)
total += ar[i]; //ar[i] 與 *(ar + i) 相同
return total;
}
int sump(int* start, int* end) //指針表示法
{
int total = 0;
while (start < end)
{
total += *start++;
}
return total;
}
運行結果
const用法
- 如果編寫的函數需要修改數組,那麼聲明數組形參時不使用 const;如果編寫的函數不用修改數組,那麼聲明數組形參時最好使用 const。
int sum(const int ar[], int n); //不需要修改原數組
int sum1(int ar[], int n); //需要修改原數組
- 指向 const 的指針不能用於改變值。
int rates[2] = {1,2};
const int* p = rates;
*p = 123; //不允許
p[1] = 3; //不允許
rates[1] = 3; //允許
p++; //可以讓指針指向別處
- 非 const 數據的地址既可以賦給普通指針又可以賦給指向 const 的指針,const 數據的地址只能賦給指向 const 的指針。
int arr[3] = {1,2,3};
const int locked[4] = {5,6,7,8};
int* p = arr; //有效
const int* pn = arr; //有效
pn = &arr[2]; //有效
p = locked; //無效
pn = locked; //有效
- 聲明並初始化一個不能指向別處的指針。
int array[3] = {32,12,34};
int* const p = array;
const int* const p1 = array; //既不能改變指針指向的地址又不能改變地址上的值
p = &array[2]; //無效
*p = 11; //有效
*p1 = 12; //無效
p1 = &array[2]; //無效