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

零基礎(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)建空間,所以無論【】{}            //中的值為多少,都能達到目的~
 
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é)果也是一樣的,所以是否有*都可以達到相同的目的,但是*代表著解引用,容易理解~

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

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)文章

  • 華為云開發(fā)工具CodeArts IDE for C/C++開發(fā)使用指南

    華為云開發(fā)工具CodeArts IDE for C/C++開發(fā)使用指南

    CodeArts IDE是一個集成開發(fā)環(huán)境(IDE),它提供了開發(fā)語言和調(diào)試服務(wù),本文主要介紹了華為云開發(fā)工具CodeArts IDE for C/C++ 開發(fā)使用指南,感興趣的可以了解一下
    2023-08-08
  • C++實現(xiàn)LeetCode(163.缺失區(qū)間)

    C++實現(xiàn)LeetCode(163.缺失區(qū)間)

    這篇文章主要介紹了C++實現(xiàn)LeetCode(163.缺失區(qū)間),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • C語言深入回顧講解結(jié)構(gòu)體對齊

    C語言深入回顧講解結(jié)構(gòu)體對齊

    C 數(shù)組允許定義可存儲相同類型數(shù)據(jù)項的變量,結(jié)構(gòu)是 C 編程中另一種用戶自定義的可用的數(shù)據(jù)類型,它允許你存儲不同類型的數(shù)據(jù)項,本篇讓我們來了解C 的結(jié)構(gòu)體內(nèi)存對齊
    2022-06-06
  • C++詳解PIMPL指向?qū)崿F(xiàn)的指針

    C++詳解PIMPL指向?qū)崿F(xiàn)的指針

    PIMPL 是 C++ 中的一個編程技巧,意思為指向?qū)崿F(xiàn)的指針。具體操作是把類的實現(xiàn)細節(jié)放到一個單獨的類中,并用一個指針進行訪問
    2022-07-07
  • C語言中隨機數(shù)rand()函數(shù)詳解

    C語言中隨機數(shù)rand()函數(shù)詳解

    大家好,本篇文章主要講的是C語言中隨機數(shù)rand()函數(shù)詳解,感興趣的同學(xué)感快來看一看吧,對你有幫助的話記得收藏一下
    2022-02-02
  • c++中vector<int>和vector<int*>的用法及區(qū)別

    c++中vector<int>和vector<int*>的用法及區(qū)別

    這篇文章主要介紹了c++中vector<int>和vector<int*>的用法及區(qū)別,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2013-10-10
  • 基于Windows C++ 應(yīng)用程序通用日志組件的使用詳解

    基于Windows C++ 應(yīng)用程序通用日志組件的使用詳解

    眾所周知,在調(diào)試、跟蹤和執(zhí)行應(yīng)用程序的過程中,程序的日志能為這些工作提供大量有價值的運行信息。因此,程序的日志對應(yīng)用程序的運行、維護至關(guān)重要
    2013-05-05
  • C++11中的智能指針shared_ptr、weak_ptr源碼解析

    C++11中的智能指針shared_ptr、weak_ptr源碼解析

    本文是基于gcc-4.9.0的源代碼進行分析,shared_ptr和weak_ptr是C++11才加入標(biāo)準(zhǔn)的,僅對C++智能指針shared_ptr、weak_ptr源碼進行解析,需要讀者有一定的C++基礎(chǔ)并且對智能指針有所了解
    2021-09-09
  • C/C++實現(xiàn)貪吃蛇逐步運動效果

    C/C++實現(xiàn)貪吃蛇逐步運動效果

    這篇文章主要為大家詳細介紹了C/C++實現(xiàn)貪吃蛇逐步運動效果的相關(guān)資料,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-05-05
  • 淺談C++左值引用和右值引用

    淺談C++左值引用和右值引用

    這篇文章主要介紹了C++左值引用和右值引用,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04

最新評論

平昌县| 嘉祥县| 上犹县| 慈溪市| 都兰县| 常山县| 永仁县| 永城市| 鹤壁市| 修武县| 广丰县| 江川县| 佛山市| 莒南县| 彭州市| 霍林郭勒市| 油尖旺区| 曲阜市| 银川市| 嘉禾县| 依兰县| 康定县| 泽普县| 锦屏县| 佛学| 漠河县| 肥乡县| 商都县| 教育| 金门县| 嘉义县| 绥德县| 虹口区| 太仓市| 朔州市| 五峰| 济宁市| 河北省| 宁陕县| 西吉县| 竹北市|