最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C語言進(jìn)階學(xué)習(xí)之指針

 更新時間:2021年09月29日 08:47:24   作者:和太陽肩并肩的老楊  
關(guān)于指針,其是C語言的重點,C語言學(xué)的好壞,其實就是指針學(xué)的好壞。其實指針并不復(fù)雜,學(xué)習(xí)指針,要正確的理解指針,本片文章能給就來學(xué)習(xí)一下

1.指針概念回顧

指針的基本概念:

指針是一個變量,用來存放地址,地址唯一標(biāo)識一塊內(nèi)存空間。指針的大小是固定的4/8個字節(jié)(32位平臺/64位平臺)。指針是有類型,指針的類型決定了指針的±整數(shù)的步長,指針解引用操作的時候的權(quán)限。不能對沒有初始化的指針或者是空指針進(jìn)行間接訪問

2.字符指針

指針類型為 char* 的指針就是字符指針

字符指針指向的對象的類型為字符型

一般使用方法:

    char ch = 'a';
	char* p = &ch; //取ch的地址放到指針變量p中

另外一種常見使用方法:

char* p2 = "bcdef"; 

對于第二種使用方法我們需要注意的是

p2實際存放的只是字符串首字符的地址,即p2存放的是字符b的地址。

在這里插入圖片描述

我們來看一道經(jīng)典的面試題:

#include <stdio.h>
int main()
{
	char str1[] = "hello yang.";
	char str2[] = "hello yang.";
	char* str3 = "hello yang.";
	char* str4 = "hello yang.";
	if (str1 == str2)
		printf("str1 and str2 are same\n");
	else
		printf("str1 and str2 are not same\n");

	if (str3 == str4)
		printf("str3 and str4 are same\n");
	else
		printf("str3 and str4 are not same\n");
	return 0;
}

str3和str4指向的都是字符串H的地址

當(dāng)指針指向同一個字符串的時候,它們實際會指向同一塊內(nèi)存。但是用相同的常量字符串去初始化不同的數(shù)組的時候就會開辟出不同的內(nèi)存塊。

因此它的答案為

在這里插入圖片描述

3.數(shù)組指針和指針數(shù)組

指針數(shù)組是一個存放指針的數(shù)組

例如

int* arr1[10]; //整形指針的數(shù)組
char *arr2[4]; //一級字符指針的數(shù)組
char **arr3[5]; //二級字符指針的數(shù)組

3.1數(shù)組指針的含義

數(shù)組指針是指針?還是數(shù)組?

答案是:指針。

int *p1[10];
int (*p2)[10];
//p1, p2分別是什么?

這里就不得不談?wù)摰絻?yōu)先級了,優(yōu)先級從大到小的順序為: “( )” > “[ ]” > “ * ”

首先看int *p1[10]; , 由于[ ]的優(yōu)先級大于*,因此p1先與“[” 結(jié)合,故而p1首先它是一個數(shù)組,它是一個存放了10個指針變量的數(shù)組。

再來看int (*p2)[10];, 由于()的優(yōu)先級大于 [ ], 先看()里的,p2與 * 結(jié)合,故而篇是一個指針,它指向了一個存放了10個整型的數(shù)組

3.2&數(shù)組名vs數(shù)組名

對于下面這個代碼

#include <stdio.h>
int main()
{
    int arr[5] = {0};
    printf("%p\n", arr);
    printf("%p\n", &arr);
    return 0;
}

arr 和 &arr 有什么區(qū)別呢?

其運行結(jié)果如下:

在這里插入圖片描述

如果你認(rèn)為它們代表的含義是正確的,不妨試著運行下面這個代碼

#include <stdio.h>
int main()
{
	int arr[5] = { 0 };
	printf("arr = %p\n", arr);
	printf("&arr= %p\n", &arr);
	printf("arr+1 = %p\n", arr + 1);
	printf("&arr+1= %p\n", &arr + 1);
	return 0;
}

我的編譯器下運行結(jié)果如下

在這里插入圖片描述

如果 arr 和 &arr 代表的含義一樣,那么后面兩個的結(jié)果應(yīng)該也是一致的,但是卻不一樣。

實際上: &arr 表示的是整個數(shù)組的地址,而不是數(shù)組首元素的地址。

數(shù)組的地址+1,跳過整個數(shù)組的大小,所以 &arr+1 相對于 &arr 的差值是40

在這里插入圖片描述

在這里插入圖片描述

3.3數(shù)組指針

數(shù)組指針就是一個指向數(shù)組的指針,意味著,這個指針內(nèi)存放的是數(shù)組的地址

#include <stdio.h>
int main()
{
    int arr[10] = {1,2,3,4,5,6,7,8,9,0};
    int (*p)[10] = &arr;//把數(shù)組arr的地址賦值給數(shù)組指針變量p
    return 0; 
}

我們來使用下指向一維數(shù)組的數(shù)組指針

//使用函數(shù)打印數(shù)組內(nèi)的內(nèi)容
# include <stdio.h>
void print_arr(int(*p)[10], int sz) //傳過來的是數(shù)組的地址,用指針來接收
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", (*p)[i]); //先解引用找到數(shù)組
	}
}
int main(void)
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };
	int sz = sizeof(arr) / sizeof(arr[0]); //求出數(shù)組的元素個數(shù)
	print_arr(&arr, sz);
	return 0;
}

4.數(shù)組傳參和指針傳參

在寫代碼的過程中,為了更好地利用模塊化的特點,我們會使用大量的函數(shù)。但是在將一個功能封裝成函數(shù)的過程中,我們就不可避免的會傳過去數(shù)組和指針,那么函數(shù)是如何接受的呢?

4.1一維數(shù)組傳參

以下是常見的一維數(shù)組傳參

#include <stdio.h>
void test(int arr[]) //直接用數(shù)組接收,空間大小可以省略
{}
void test(int arr[10]) //直接用數(shù)組接收,空間大小可以指明
{}
void test(int *arr) //接收數(shù)組首元素的地址
{}
void test2(int *arr[20]) //直接用數(shù)組接收
{}
void test2(int **arr) //傳過來一級指針的地址,使用二級指針接收
{}
int main()
{
 int arr[10] = {0};
 int *arr2[20] = {0}; //存放了20個int*的數(shù)組
 test(arr); //傳過去的是首元素的地址
 test2(arr2);
}

4.2二維數(shù)組傳參

當(dāng)我們在談?wù)摱S數(shù)組首元素的時候指的是第一行!
數(shù)組名是首元素的地址,在二維數(shù)組中指的是第一行的地址

void test(int arr[3][5])//直接用二維數(shù)組接收
{}
void test(int arr[][])//錯誤的接收!列不能省略
{}
void test(int arr[][5])//行是可以省略的,但是列一定不能省略
{}
//總結(jié):二維數(shù)組傳參,函數(shù)形參的設(shè)計只能省略第一個[]的數(shù)字。
//因為對一個二維數(shù)組,可以不知道有多少行,但是必須知道一行多少元素。
//這樣才方便運算。
void test(int *arr)//錯誤接收!傳過來的是第一行一維數(shù)組的地址
{}
void test(int* arr[5])//錯誤接收!這是一個存放int*類型的數(shù)組,而數(shù)組內(nèi)的元素是int
{}

//由于二維數(shù)組的首元素是第一行,每一行是一個一維數(shù)組
//因此可以寫成指向一維數(shù)組的指針
void test(int (*arr)[5])
{}
void test(int **arr) //錯誤!
{}
int main()
{
 int arr[3][5] = {0};
 test(arr);
}

4.3一級指針傳參

#include <stdio.h>
void print(int *p, int sz) {
 int i = 0;
 for(i=0; i<sz; i++)
 {
 printf("%d\n", *(p+i));
 }
}
int main()
{
 int arr[10] = {1,2,3,4,5,6,7,8,9};
 int *p = arr;
 int sz = sizeof(arr)/sizeof(arr[0]);
 //一級指針p,傳給函數(shù)
 print(p, sz);
 return 0; }

4.4二級指針傳參

#include <stdio.h>
void test(int** ptr)
{
	printf("num = %d\n", **ptr);
}
int main()
{
	int n = 10;
	int* p = &n;
	int** pp = &p;
	test(pp);
	test(&p);
	return 0;
}

5.函數(shù)指針

在之前的學(xué)習(xí)當(dāng)中不會每天使用函數(shù)指針,但是請不要忘記它的存在。
什么是函數(shù)指針?顧名思義,函數(shù)指針就是指向一個函數(shù)的指針。既然函數(shù)指針是指針,那么它也具有指針的一些特性。比如:在對指針進(jìn)行間接訪問之前必須要先初始化

//代碼一
int f(int);//f函數(shù)
int (*pf)(int) = &f;

這是函數(shù)初始化的一種方法。

//代碼二
int f(int);
int (*pf)(int) = f;

代碼一和代碼二是等效的。我們用下面一個代碼查看,發(fā)現(xiàn)其打印出來的地址是一樣的。

在這里插入圖片描述

在數(shù)組中,數(shù)組名是數(shù)組首元素的地址。而函數(shù)名則是函數(shù)的首地址。在函數(shù)名使用的時候我們所用的編譯器會將函數(shù)名轉(zhuǎn)化為一個函數(shù)指針,&操作符只是顯示地說明了函數(shù)將隱式執(zhí)行的任務(wù)。

如果你需要將函數(shù)的地址存儲起來,這個時候你就可能會需要用到函數(shù)指針了

void test()
{
	printf("hehe\n");
}
//下面的哪一個語句有能力存放函數(shù)test的地址呢?
void (*pfun1)(); //語句1
void *pfun2(); //語句2

存儲地址應(yīng)該需要用到的是指針

語句1:

pfun1首先和 * 操作符結(jié)合,那么它是一個指針。后面有一個函數(shù)調(diào)用操作符,表明它是一個函數(shù)指針。它所指向的函數(shù)

返回值類型是void

語句2:

pfun2首先和()結(jié)合,那么它是一個函數(shù)。 *和前面的void結(jié)合,表明這個函數(shù)的返回值類型是void*

所以選擇語句1。

6.函數(shù)指針數(shù)組

我們知道數(shù)組是存儲一組相同類型的數(shù)據(jù),在此之前我們再來回顧一下指針數(shù)組

int *arr[10];
//數(shù)組的每個元素是int*

這是一個數(shù)組,數(shù)組存放了10個int*類型的數(shù)據(jù)。

按照這個思路,我們把很多函數(shù)的地址存放在數(shù)組中,那么它就是一個函數(shù)指針數(shù)組。

下面我們一起來實現(xiàn)它

首先它是一個數(shù)組 [ ], 存放的數(shù)據(jù)類型為函數(shù)指針,int (*)()類型的是函數(shù)指針

int (*parr1[10])();
int *parr2[10]();
int (*)() parr3[10];

7.指向函數(shù)指針數(shù)組的指針

經(jīng)過我們上面這么多的推導(dǎo),這個也就很容易就能表示出來

指向函數(shù)指針數(shù)組的指針是一個 指針, 指針指向一個 數(shù)組 ,數(shù)組的元素都是 函數(shù)指針

void test(const char* str)
{
 printf("%s\n", str);
}
int main()
{
 //函數(shù)指針pfun
 void (*pfun)(const char*) = test;
 //函數(shù)指針的數(shù)組pfunArr
 void (*pfunArr[5])(const char* str);
 pfunArr[0] = test;
 //指向函數(shù)指針數(shù)組pfunArr的指針ppfunArr
 void (*(*ppfunArr)[10])(const char*) = &pfunArr;
 return 0;
}

8.回調(diào)函數(shù)

回調(diào)函數(shù):回調(diào)函數(shù)就是將一個函數(shù)的函數(shù)指針作為參數(shù)傳遞給另一個函數(shù),而這個函數(shù)就是回調(diào)函數(shù)。

回調(diào)函數(shù)不是由該函數(shù)的實現(xiàn)方直接調(diào)用,而是在特定的事件或條件發(fā)生時由另外的一方調(diào)用的,用于對該事件或條件進(jìn)行響應(yīng)。

庫函數(shù)中的qsort函數(shù)就是一個典型的回調(diào)函數(shù)

總結(jié)

本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!

相關(guān)文章

最新評論

包头市| 彭阳县| 乌恰县| 巨野县| 六安市| 延庆县| 阿克苏市| 三都| 镇远县| 陈巴尔虎旗| 介休市| 香格里拉县| 洱源县| 芮城县| 邛崃市| 乃东县| 苗栗县| 禄劝| 沙田区| 思南县| 如东县| 灵石县| 五寨县| 榆中县| 宁陕县| 翼城县| 旬阳县| 奉新县| 岳阳县| 柳江县| 绥中县| 乐东| 临沧市| 长治县| 宝鸡市| 宾川县| 谷城县| 安陆市| 揭阳市| 阿尔山市| 土默特右旗|