1.定義指針變量
數據在內存中的地址也稱爲指針,如果一個變量存儲了一份數據的指針,我們就稱它爲指針變量。
int a = 1;
int *p = &a;
通過指針變量p獲取數據:
printf("%d", *P);
星號*主要有三種用途:
1)表示乘法,例如int a = 1, b = 2, c; c = a * b;,這是最容易理解的
2)表示定義一個指針變量,以和普通變量區分開,例如int a = 100; int *p = &a;
3)表示獲取指針指向的數據,是一種間接操作,例如*p = 100; b = *p;
2.指向數組的指針
Array是一系列具有相同類型的數據的集合,每一份數據叫Element(數組元素)。數組中的所有元素在內存中是連續排列的。
如:
int arr[] = {1,2,3,4,5,6};
定義數組時,要給出數組名和數組長度,數組名可以認爲時一個指針,它指向數組的第0個元素。
*(arr + 1) 獲取的數據和arr[1]等價
arr本身是一個指針,可以直接賦值給指針變量p:
int *p = arr;
指針疑惑
*p++ 等價於*(p++),表示先取得第n個元素的值,再將p指向下一個元素
*++P 等價於*(++p),會先進行++p運算,使得p的值增加,指向下一個元素,整體上相當於*(p+1)
(*p)++ 等價於對指針變量p獲取的數值做加1操作。
3.字符串指針(指向字符串的指針)
c語言沒有特定的字符串類型,我們通常時將字符串放在一個字符數組中。
int main()
{
char str[] = "Say Hello!";
int len = strlen(str);
printf("%s\n", str);
for(int i = 0; i < len; i++){
printf("%c", str[i]);
}
}
指針和數組的規則同樣也適用於字符數組:
int main()
{
char *str = "Say Hello!";
int len = strllen(str);
printf("%s\n", str);
for(int i = 0; i < len; i++){
printf("%c", str[i]);
//使用*(str + i)
printf("%c", *(str + i));
}
}
C語言有兩種表示字符串的方法,
1)是字符數組:字符數組存儲在全局數據區或棧區,使得字符數組可以讀取和修改
char str[] = "Say Hello!";
str = "you you!"; //正確
str[1] = 'A' //正確
2)是字符串常量:字符串存儲在常量區,只能讀取不能修改
char *str = "Say Hello!";
str = "you you!"; //正確,可以更改指針變量本身的指向。
str[1] = 'A'; //錯誤,不能對常量進行寫入。
*(str + 1) = 'A'; //錯誤,不能對常量進行寫入。
4.指針變量作爲函數參數
#include <stdio.h>
void swap(int *p1, int *p2){
int temp; //臨時變量
temp = *p1;
*p1 = *p2;
*p2 = temp;
}
int main(){
int a = 1, b = 2;
swap(&a, &b);
printf("a = %d, b = %d\n", a, b);
return 0;
}
5.指針作爲函數返回值
C語言允許函數的返回值是一個指針(地址),我們將這樣的函數稱爲指針函數。
int *max(int *a, int *b)
{
if (*a > *b) {
return a;
}
else{
return b;
}
}
int main()
{
int a = 10;
int b = 20;
int *c = max(&a, &b);
printf("max num is %d\n", *c);
}
6.二級指針(指向指針的指針)
指針變量也是一種變量,也會佔用存儲空間,也可以使用&獲取它的地址。C語言不限制指針的級數,每增加一級指針,在定義指針變量時就得增加一個星號*。p1 是一級指針,指向普通類型的數據,定義時有一個*;p2 是二級指針,指向一級指針 p1,定義時有兩個*。
int main()
{
int a = 1;
int *p1 = &a;
int **p2 = &p1;
printf("%d, %d, %d", a, *p1, **p2);
}
解析:*p2指向的是指針變量p1的值,**p2是指針變量p1的獲取數據的值(*p1)
7.指針數組
如果一個數組中的所有元素保存的都是指針,那麼我們就稱它爲指針數組。
int main()
{
//整形指針數組
int a = 1, b = 2, c = 3;
//定義一個指針數組
int *arr[3] = {&a, &b, &c}; //可以不指定長度
//定義一個指向指針數組的指針
int **parr = arr;
printf("%d, %d, %d\n", *arr[0], *arr[1], *arr[2]);
printf("%d, %d, %d\n", **(parr+0), **(parr+1), **(parr+2));
//字符串數組和指針數組
char *str[3] = {
"hello one!",
"hello two!",
"hello three!"
}
printf("%s\n%s\n%s\n", str[0], str[1], str[2]);
//字符串指針數組
char *str0 = "hello one!";
char *str1 = "hello two!";
char *str2 = "hello three!";
char *str[3] = {str0, str1, str2};
printf("%s\n%s\n%s\n", str[0], str[1], str[2]);
return 0;
}
8.二維數組指針
int main()
{
int a[2][2] = {{1,2}, {3,4}};
//定義一個指向a的指針變量p;
int (*p)[2] = a; //括號中*表明p是一個指針,它指向一個數組。[]的優先級高於*,所以()是必須要加的。如果寫成*p[2]就成指針數組了。
printf("%zu\n", sizeof(*(p+1)));
int i,j;
for(i=0; i<2; i++){
for(j=0; j<2; j++)
printf("%2d ",*(*(p+i)+j));
//printf("%2d ", (*(p + i))[j]);
printf("\n");
}
return 0;
}
9.函數指針
一個函數總是佔用一段連續的內存區域,函數名在表達式中有時也會被轉換爲該函數所在內存區域的首地址,這和數組名非常類似。我們可以把函數的這個首地址(或稱入口地址)賦予一個指針變量,使指針變量指向函數所在的內存區域,然後通過指針變量就可以找到並調用該函數。這種指針就是函數指針。
#include <stdio.h>
//返回兩個數中較大的一個
int max(int a, int b){
return a>b ? a : b;
}
int main(){
int a = 1, b = 2;
//定義函數指針
int (*pmax)(int a, int b) = max;
int maxFunc = (*pmax)(a, b);
printf("maxFunc: %d\n", maxFunc);
return 0;
}
pmax 是一個函數指針,在前面加 * 就表示對它指向的函數進行調用