欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

零基礎(chǔ)詳解C語言指針進階

 更新時間:2022年02月09日 14:34:46   作者:誠摯的喬治  
在C語言和C++等語言中,數(shù)組元素全為指針變量的數(shù)組稱為指針數(shù)組,指針數(shù)組中的元素都必須具有相同的存儲類型、指向相同數(shù)據(jù)類型的指針變量。指針數(shù)組比較適合用來指向若干個字符串,使字符串處理更加方便、靈活

前言

這是指針的進階,如果想入門指針的朋友可以關(guān)注我的另外一篇文章—c語言 指針零基礎(chǔ)講解

堅持看完,一定會有很大的收獲~~

那接下來—起航

1.字符指針

我們目前知道整形指針,浮點型指針,字符指針跟他倆類型

字符指針—顧名思義就是指針,一個char*類型的指針 

??在講解字符指針前,我先提一下怎么連續(xù)創(chuàng)建多個指針

連續(xù)創(chuàng)建多個指針的方法:

你可能會想到用:

int a ,b;
 
int* a,b;

或者

#define PINT int*
 
int main(){
 
int a ,b;
 
p a,b;
 
}

但是實際上這樣創(chuàng)建的結(jié)果是:

創(chuàng)建一個整形指針int*a與整形變量int b.

創(chuàng)建指針的正確打開方式:

//方案一,直接定義兩次
int a,b;
int*a; int*b;
//方案二,采用typedef重定義
typedef int* pint
{
	int a,b;
pint pa, pb;//此時就是定義int *pa與int *pb都是指針變量
return 0;
}

下面給出一個簡單的代碼:

char ch='w';
char* p=ch;
char* p="abcde";

定義一個char類型的變量ch,將ch地址放在指針變量p中

此時p存放的就是字符w的地址

這個很容易理解,那么char* p="abcde"是什么意思呢

實際上這次的p存放的是字符串a(chǎn)bcde的首元素的地址,也就是a的地址

有了首地址,就很容易找到后續(xù)元素的地址

例題 1

    判斷下面代碼是否相等
    char arr1[] = "abcdef";
    char arr2[] = "abcdef";
 
    const char* str1 = "abcdef";
    const char* str2 = "abcdef";
#include<stdio.h>//證明相等關(guān)系
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "abcdef";
	const char* str1 = "abcdef";
	const char* str2 = "abcdef";
	if (arr1 == arr2)
		printf("arr1==arr2\n");
	else
		printf("arr1!=arr2\n");
	if (str1 == str2)
		printf("str1==str2\n");
	else
		printf("str1!=str2\n");
 
	return 0;
}

為什么arr1!=arr2; str1==str2

首先創(chuàng)建數(shù)組,arr1與arr2,先向系統(tǒng)申請兩個不同的空間,然后將abcdef放入兩個不同的空間里,所以這兩個空間的地址當(dāng)然就不相同

其次是str1與str2的abcdef只存儲在只讀存儲區(qū)(這跟const無關(guān),const起到強調(diào)的作用,實際上有無const的意思是相同的),就是不能更改其中的元素;

這時候兩字符串的內(nèi)容相同,系統(tǒng)就不會在浪費多余的空間去儲存兩個不同的內(nèi)容~

所以就形成str1==str2,實際上這兩個變量儲存的都是a的地址

2.指針數(shù)組

在這之前我們知道整形數(shù)組,浮點型數(shù)組等

意思就是儲存整形與浮點型數(shù)子的數(shù)組

指針數(shù)組就是存放指針的數(shù)組,實際上還是數(shù)組,里面存放著不同類型的指針

int*arr[5];//整形指針數(shù)組
char*arr[5];//一級字符指針數(shù)組
char**arr[5];//二級字符指針數(shù)組

知道定義,那如何使用呢

例題 2

多組打印字符串

#include<stdio.h>
int main()//指針數(shù)組
{
	char* arr[] = { "abcdef","ghi" ,"jklmn" };
	//打印
	int i = 0;
	int sz = sizeof (arr) / sizeof (arr[0]);
	for (i = 0; i < sz; i++)
	{
		printf("%s\n",arr[i]);
	}
	return 0;
}

其中的    char* arr[] = { "abcdef","ghi" ,"jklmn" }就是指針數(shù)組,存放的就是char類型的指針,

他的作用就相當(dāng)于:

char arr1[] = "abcdef";
char arr2[] = "ghi";
char arr3[] = "jklmn";

打印的結(jié)果就是:

??打印整形的數(shù)組

#include<stdio.h>
int main()
{
	//打印整形數(shù)
	int arr1[] = { 1, 2, 3, 4, 5};
	int arr2[] = { 2, 3, 4, 5, 6};
	int arr3[] = { 3, 4, 5, 6, 7};
	int* arr[] = { arr1,arr2,arr3 };
	int i = 0; int j = 0;
	for (i = 0; i < 3; i++)
	{
		for (j = 0; j < 5; j++)
		{
			printf("%d", arr[i][j]);
		}
		printf("\n");
	}
	return 0;
}

3.數(shù)組指針

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

有了指針數(shù)組的概念,相信很多人就知道數(shù)組指針的概念

跟你們想的一樣

數(shù)組指針—就是指針,什么指針呢,存放數(shù)組的指針

int *pint;//能夠指向整形數(shù)據(jù)的指針
char *p;//能夠指向字符數(shù)據(jù)的指針
char (*p)[10];能夠指向數(shù)組的指針

它的類型包括int(*)[],  char(*)[]

解讀一下,其中的(*)就代表是一個指針[]就代表是一個數(shù)組的指針,char或者int就代表數(shù)組中的數(shù)據(jù)是啥類型的元素

??那么int * p1[10]與 int (*) p2[10]

其中的p1 p2是什么意思呢

前者是一個數(shù)組(指針數(shù)組)變量

后者是一個指針(數(shù)組指針)變量

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

我們知道數(shù)組名就是首元素的地址(數(shù)組名直接與sizeof相連與&數(shù)組名除外)

那么&數(shù)組名是什么意思呢

實際上&數(shù)組名就是整個數(shù)組的地址

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

有打印的結(jié)果中很容易看出

arr 與 arr+1隔四個字節(jié),也就是一個整形的大小

而&arr與&arr+1之間隔八十個字節(jié),就是二十個整形的大小

??接下來在看一個代碼

int *p[10];
int *(*pp)[10];

此時的int *p[10],p就是指針數(shù)組變量

int *(*pp)[10]這句的意思就是定義一個指針變量,什么指針?數(shù)組指針,而這個數(shù)組里的元素都是int*,有十個int*類型的數(shù)據(jù)。這就是數(shù)組指針~~

故arr在一般情況下都是這個數(shù)組首元素的地址,&arr就是整個數(shù)組的地址

3.3 數(shù)組指針的使用

說完數(shù)組指針的定義和使用規(guī)則,下面講解數(shù)組指針的使用

給定三個數(shù)組,分別打印出他們的值

#include<stdio.h>
print(int (*p)[5],int r,int c)//此時的int (*p)[5]就是一個數(shù)組指針
{
	int i = 0; int j = 0;
	for(i=0;i<r;i++)
	{
		for(j=0;j<c;j++)
		{
			printf("%d", *(*(p+i) + j)); //*(p+i)就相當(dāng)于拿到第一行的地址
		}
	printf("\n");
	}
 
}
int main()
{
	//打印數(shù)字
	int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };
	print(arr,3,5);
	return 0;
}

打印的結(jié)果:

這道題運用了一個二維數(shù)組

在這里我將二維數(shù)組看作是一維數(shù)組,也就是把一行當(dāng)作一個元素

所以此數(shù)字有三個元素

就算是說二維數(shù)組的數(shù)組名就是第一行的的地址

 當(dāng)然一維數(shù)組里也可以用到數(shù)組指針的思想,但實際上也不需要,這樣反而變得麻煩,反而在二維數(shù)組中可以很好的利用。

那下面來總結(jié)一下:

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

int *arr

是一個指針,類型是int*的指針;

int *parr1[10]

是一個數(shù)組,數(shù)組的類型是int *[],且是一個指針數(shù)組

int (*parr2)[10]

是一個指針,指針的類型是int(*)[],且是一個指針數(shù)組,數(shù)組中有十個整形元素

int(*parr3[10])[10]

是一個數(shù)組,此時把parr3去掉就得到nt(*)[],這里就是一個數(shù)組指針,所以這是一個存有十個數(shù)組指針的數(shù)組。

4.數(shù)組與指針在函數(shù)里的傳參

函數(shù)傳參的前提就是形參與實參是對應(yīng)的關(guān)系,也就是說實參是什么類型,那么形參也是相應(yīng)的類型,比如說實參是數(shù)組,那形參就是數(shù)組,參數(shù)是指針,那么形參也是指針。

4.1 一維數(shù)組的傳參

#include<stdio.h>
test(arr1[])
{}
test(arr1[10])//上面兩種方法,實參是數(shù)組,用數(shù)組來接收,因為在函數(shù)中本身不創(chuàng)建空間,所以無論【】{}            //中的值為多少,都能達(dá)到目的~
 
test(*arr1)
{}          //前面我提到數(shù)組名就是首元素的地址,此時就把實參中的數(shù)組名當(dāng)作首元素的地址,此時用指 
            //針來接收
 
test(*arr2[10])
{}          //這里也跟第一二兩個相同,也是數(shù)組傳參,數(shù)組來接收
 
test(**arr2)
{}          //這里采用二級指針來接收,實參是一級指針,那么一級指針的指針就可以用二級指針來接收
int main()
{
int arr1[10]={0};
int* arr2[10]={0};
test(arr1);
test(arr2);
return 0;
}

4.2 二維數(shù)組的傳參

#include<stdio.h>
//通過數(shù)組
test(int arr[10][10])      //二級指針傳參時以數(shù)組的形式,【】中的行可以省略,但是列不能省略
{}                         //列可以讓系統(tǒng)知道一行有多少的元素,從而分配多少的空間,便于知道每一 
                           //個元素的地址,故test(int arr[10][10])與test(int arr[][10])是可以 
                           //進行傳參的,但是test(int arr[][])顯然是不可以的。
test(int arr[][])
{}
test(int arr[][10])
{}
//通過指針
test(int *arr)
{}
test(int (*arr)[10])      //我們知道實參傳的是首元素的地址,這里的首元素的地址就是第一行元素的 
{}                        //地址,也就是數(shù)組的地址,所以需要數(shù)組指針來接收
                          //故需要test(int (*arr)[10])來接收,而一級指針與二級指針顯然是不可的 
 
test(int** arr)
{}
int main()//二級指針傳參
{
	int arr[10][10] = { 0 };
	test(arr);
	return 0;
}

4.3 一級指針的傳參

#include<stdio.h>
test(int *p)
{}
int main()
{
	int a = 10;
	int* par = &a;
	int arr[10];
 
	test(par);
	test(arr);
	test(*a);      //當(dāng)一級指針傳參時,形參是指針,那么實參就可以用這三種方式傳參
 
	return 0;
}

4.4 二級指針的傳參

#include<stdio.h>     //當(dāng)二級指針傳參時,形參是二級指針,那實參有哪些方式呢
test(int** p)
{}
int main()
{
	//二級指針傳參
	char a = 'w';
	char* p = &a;
	char** pp = &p;
	char* arr[10] = { 0 };
 
	test(&p);        //通過一級指針p的取地址
	test(pp);        //通過二級指針傳參,用二級指針來接收
	test(arr);       //通過char*()類型指針數(shù)組名來傳遞
 
	return 0;
}

5.函數(shù)指針

數(shù)組指針就是數(shù)組的地址

那么函數(shù)指針也是存放函數(shù)地址

??那問題是函數(shù)有指針嗎

#include<stdio.h>
int Add(int x,int y)
{
	int sum = 0;
	sum = x + y;
}
int main()
{
	//證明函數(shù)有地址
	int a = 0;
	int b = 0;
	printf("%p", &Add);
    printf("%p\n", Add);
//定義一個函數(shù)指針變量
    int (*pf)(int,int)=&Add;  //此時的pf就是函數(shù)的指針變量,用pf就可以調(diào)用函數(shù)
	return 0;                 //括號中是參數(shù)的類型
}

這段代碼證明,函數(shù)也有地址,而且取地址加函數(shù)名與函數(shù)名的作用是相同的,既然函數(shù)有地址就可以通過指針調(diào)用這個函數(shù)

調(diào)用這個函數(shù):

#include<stdio.h>
int  Add(int x,int y)
{
	int sum = 0;
	sum = x + y;
	return sum;
}
int main()
{
	int (*pf)(int,int) = &Add;
	int ret1=(*pf)(2, 3); //括號別忘了
	int ret2 = (pf)(2, 3);//這里的括號可以省略
	printf("%d\n", ret1);
	printf("%d\n", ret2);
 
	return 0;
}

打印的結(jié)果:

可以看到,主函數(shù)中的pf與*pf的使用效果是一樣的,打印的結(jié)果也是一樣的,所以是否有*都可以達(dá)到相同的目的,但是*代表著解引用,容易理解~

下面給出了一個有趣的代碼:

void(* signal (int,void (*) (int)) )(int)

這段代碼的意思是什么呢,是不是看著有點暈

實際上把signal (int,void (*) (int))提出來剩下的就是void(*)(int),其中的signal是函數(shù)聲明。

首先這是一個函數(shù)指針,有兩個參數(shù),一個參數(shù)是int,還有一個是函數(shù)指針,其返回值就是void(*)(int),也就是一個函數(shù)指針。

這個函數(shù)可以簡化一下,也就是把void(*)(int)重新定義為一個新的變量

你可能認(rèn)為是typedef void(*)(int)  pfun_t

這樣的確好理解一些,畢竟跟我們所學(xué)習(xí)的結(jié)構(gòu)體是一樣的

但是真正的結(jié)果是typedef void(*pfun_t)(int) ,其中的pfun_t放在中間,我這樣學(xué)也起到了強調(diào)的作用。

void(* signal (int,void (*) (int)) )(int)簡化的結(jié)果是pfun-t signal(int,void (*) (int))

pfun-t是類型名,并不是類型名

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

前面我們學(xué)了整形指針數(shù)組,字符指針數(shù)組,和他們相同,函數(shù)指針數(shù)組也是一個數(shù)組,只不過數(shù)組里的元素是整形指針。

函數(shù)指針數(shù)組可以一次性實現(xiàn)多個函數(shù)的調(diào)用

#include<stdio.h>
int Add(int x, int y)
{
	return x + y;
}
int Sub(int x, int y)
{
	return x - y;
}
int Mul(int x, int y)
{
	return x * y;
}
int Div(int x, int y)
{
	return x / y;
}
int main()
{ 
    //int (*pf1)(int, int)=&Add;
    //int (*pf2)(int, int)=&Sub;
    //int (*pf3)(int, int)=&Mul;
    //int (*pf4)(int, int)=&Div;
	int (*pfAdd[4])(int, int) = { &Add ,&Sub,&Mul,&Div };//數(shù)組指針可以很好的實現(xiàn)多次的定義
	int i = 0;
	for (i = 0; i < 4; i++)
	{
		printf("%d\n", *(pfAdd[i])(8, 4));
	}
	return 0;
}

 通過簡單的數(shù)組的調(diào)用,就可以實現(xiàn)加減乘除的運算,那函數(shù)指針數(shù)組有什么用呢

既然函數(shù)指針數(shù)組可以同時實現(xiàn)加減乘除,那當(dāng)然可以實現(xiàn)一個計算器

用函數(shù)指針數(shù)組實現(xiàn)一個計算器

 
#include<stdio.h>
int Add(int x, int y)
{
	return x + y;
}
int Sub(int x, int y)
{
	return x - y;
}
int Mul(int x, int y)
{
	return x * y;
}
int Div(int x, int y)
{
	return x / y;
}
menu()
{
	printf("*****************************************\n");
	printf("********  1.Add     2.Sub     ***********\n");
	printf("********  3.Mul     4.Div     ***********\n");
	printf("********  0.exit              ***********\n");
	printf("*****************************************\n");
 
}
int main()//用函數(shù)指針來實現(xiàn)一個計算器
{
	int x = 0;
	int y = 0;
	int input = 0;
	int ret = 0;
	int (*pfArr[5])(int, int) = { 0, &Add ,& Sub,& Mul,& Div };
	do
	{
		menu();
		printf("請選擇:>");
		scanf_s("%d", &input);
		if (input == 0)
		{
			printf("計算機以關(guān)閉");
		}
		else if (input >= 1 && input <= 4)
		{
			printf("請輸入x與y:>");
			scanf_s("%d %d", &x, &y);
			ret = pfArr[input](x, y);
			printf("%d\n", ret);
		}
		else
			printf("選擇錯誤");
	} while (input);
	return 0;
}

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

????回調(diào)函數(shù)就是通過函數(shù)指針調(diào)用的函數(shù),如果把一個函數(shù)的指針(地址)當(dāng)作參數(shù),傳給另一個函數(shù),當(dāng)這個函數(shù)調(diào)用所指的函數(shù)時,我們就說這是回調(diào)函數(shù)。

下面來用回調(diào)函數(shù)來實現(xiàn)上一次用函數(shù)指針數(shù)組實現(xiàn)的計算器

#include<stdio.h>
int Add(int x, int y)
{
	return x + y;
}
int Sub(int x, int y)
{
	return x - y;
}
int Mul(int x, int y)
{
	return x * y;
}
int Div(int x, int y)
{
	return x / y;
}
menu()
{
	printf("*****************************************\n");
	printf("********  1.Add     2.Sub     ***********\n");
	printf("********  3.Mul     4.Div     ***********\n");
	printf("********  0.exit              ***********\n");
	printf("*****************************************\n");
}
void calc(int (*pf)(int, int))
{
	int x = 0; int y = 0;
	printf("請輸入兩個數(shù):>");
	scanf_s("%d %d", &x, &y);
	int ret = pf( x, y);
	printf("%d\n", ret);
}
int main()
{ 
	int input = 0;
	do
	{
		printf("請選擇:\n");
		menu();
 		scanf_s("%d", &input);
		switch(input)
		{
		case 1:
				calc(Add);
				break;      
		case 2:
				calc(Sub);
				break;
		case 3:
				calc(Mul);
				break;
		case 4:
				calc(Div);
				break;
		case 0:
			printf("退出計算器");
			break;
		default:
			printf("選擇錯誤");
			break;
		}
	} while (input);
	return 0;
}

回調(diào)函數(shù)很好的省略了case內(nèi)部的重復(fù)代碼過程,此時的加減乘除函數(shù)的指針當(dāng)作參數(shù)傳入calc函數(shù)里,這就是回調(diào)函數(shù)。

結(jié)語:這一章,c語言的指針相關(guān)的知識就結(jié)束了

到此這篇關(guān)于零基礎(chǔ)詳解C語言指針進階的文章就介紹到這了,更多相關(guān)C語言 指針內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • VC中SendMessage和PostMessage的區(qū)別

    VC中SendMessage和PostMessage的區(qū)別

    這篇文章主要介紹了VC中SendMessage和PostMessage的區(qū)別,較為全面的分析了SendMessage和PostMessage運行原理及用法上的不同之處,非常具有實用價值,需要的朋友可以參考下
    2014-10-10
  • C/C++實現(xiàn)獲取系統(tǒng)時間的示例代碼

    C/C++實現(xiàn)獲取系統(tǒng)時間的示例代碼

    C 標(biāo)準(zhǔn)庫提供了 time() 函數(shù)與 localtime() 函數(shù)可以獲取到當(dāng)前系統(tǒng)的日歷時間。本文將通過一些簡單的示例為大家講講C++獲取系統(tǒng)時間的具體方法,需要的可以參考一下
    2022-12-12
  • OpenMP中For Construct對dynamic的調(diào)度方式詳解

    OpenMP中For Construct對dynamic的調(diào)度方式詳解

    在本篇文章當(dāng)中主要給大家介紹 OpenMp for construct 的實現(xiàn)原理,與他相關(guān)的動態(tài)庫函數(shù)分析以及對 dynamic 的調(diào)度方式進行分析,希望對大家有所幫助
    2023-02-02
  • C語言數(shù)學(xué)問題與簡單DP01背包問題詳解

    C語言數(shù)學(xué)問題與簡單DP01背包問題詳解

    這篇文章主要介紹了C語言數(shù)學(xué)問題買不到的數(shù)目、螞蟻感冒、飲料換購與簡單DP01背包問題的解決,屬于藍(lán)橋杯省賽中的題目,感興趣的同學(xué)來看看吧
    2022-04-04
  • Visual Studio Code (VSCode) 配置搭建 C/C++ 開發(fā)編譯環(huán)境的流程

    Visual Studio Code (VSCode) 配置搭建 C/C++ 開發(fā)編譯環(huán)境的流程

    記得N年前剛開始接觸編程時,使用的是Visual C++6.0,下面這個可愛的圖標(biāo)很多人一定很熟悉。不過今天想嘗鮮新的工具 Visual Studio Code 來搭建C/C++開發(fā)環(huán)境,感興趣的朋友一起看看吧
    2021-09-09
  • 使用C語言訪問51單片機中存儲器的核心代碼

    使用C語言訪問51單片機中存儲器的核心代碼

    這篇文章主要介紹了使用C語言訪問51單片機中存儲器的相關(guān)知識,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-01-01
  • Qt中樹形控件Tree Widget的使用方法匯總

    Qt中樹形控件Tree Widget的使用方法匯總

    最近小編在研究Tree Widget樹形控件的相關(guān)知識,這種控件其實有時還是很有用處的,我主要利用的是帶有復(fù)選框的樹形控件,下面通過實例代碼給大家介紹下Qt中樹形控件Tree Widget的一些使用方法,感興趣的朋友一起學(xué)習(xí)吧
    2021-11-11
  • C++ 動態(tài)創(chuàng)建按鈕及 按鈕的消息響應(yīng)

    C++ 動態(tài)創(chuàng)建按鈕及 按鈕的消息響應(yīng)

    這篇文章主要介紹了C++ 動態(tài)創(chuàng)建按鈕及 按鈕的消息響應(yīng)的相關(guān)資料,需要的朋友可以參考下
    2015-06-06
  • C語言進階教程之預(yù)處理

    C語言進階教程之預(yù)處理

    C語言提供了多種預(yù)處理功能,如宏定義、文件包含、條件編譯等,下面這篇文章主要給大家介紹了關(guān)于C語言進階教程之預(yù)處理的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-02-02
  • C語言實現(xiàn)魔方比賽管理系統(tǒng)

    C語言實現(xiàn)魔方比賽管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C語言實現(xiàn)魔方比賽管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-05-05

最新評論