前沿:
? ? ? 有人曾說過不會指針等于沒有學習c語言,而我也是非常認同這個觀點的,要想學習好c語言,指針是比不可缺少的,如果指針學不會c語言也就沒辦法學好,而向如此越重要的東西越比較難學,但難學并不代表學不會,這片文章將由簡單到復(fù)雜讓你深刻的了解指針,從此不再害怕指針的學習。
思維導(dǎo)圖:
目錄
一、指針的初步認識:
1.1指針是什么:
1.2指針的類型:
1.3指針的大?。?/p>
1.4指針的定義和使用:
?1.5野指針:
二、指針的進階認識:
2.1字符指針:
2.2指針數(shù)組:
2.3數(shù)組指針:
2.4函數(shù)指針:
2.5函數(shù)指針數(shù)組:
?總結(jié):
一、指針的初步認識:
1.1指針是什么:
? 1.1.1? 學習一個知識我們需要了解他的本質(zhì),正如我們學習指針,我們要先了解他是什么,從生活中舉例,指針就好比我們家的門牌號一樣,每個房間都有自己的門牌號,而我們則可以通過門牌號找到我們想要找到的人,別人也可以通過門牌號找到你。為此我們可以初步的了解指針就表示地址,通過指針我們可以找到相應(yīng)類型的變量。所以我們平??谡Z中的指針其實就是指針變量,是用來存放內(nèi)存地址的變量。
1.1.2 這樣我們就好理解一個變量所占的內(nèi)存叫做字節(jié),而地址指向的就是所占字節(jié)的位置也就是地址。
這里的0xFFFFFFFFF則就表示地址。
1.2指針的類型:
? ? ? ?1.2.1 像int double float char 類型一樣指針也有自己相應(yīng)的類型,而指針的類型就是指針所指向元素是什么類型,指向int的指針就是整型指針,指向char類型的就是字符型指針等等。
#include<stdio.h>
int main()
{
int a;
int *ra=&a;
char b;
char* rb=&b; //等等
return 0;
}
1.3指針的大?。?/span>
1.3.1指針的大小都是確定的在32位的編譯器下指針變量的大小都是4個字節(jié),在64位編譯器下指針的大小都是8個字節(jié)?為啥呢?要知道不管什么類型的指針都是指針變量,而指針變量都是用來存放地址的,所以指針變量的大小取決一個地址存放所需要的空間大小為此不同的編譯器有不同的大小但一般都是4/8個字節(jié)。
1.4指針的定義和使用:
#include<stdio.h>
int main()
{
int a=10; //在內(nèi)存中申請空間 我們也知道局部變量是存放在棧中的
int* p=&a; //定義一個指針,對變量a取地址用的符號是&,這里a占的字節(jié)是四個,這里是將a的4個字節(jié)的第一個字節(jié)的地址存放在p變量中,p就是一個之指針變量。
printf("%d\n",*p); //*p是對指針的解引用,得到地址所指向的數(shù)
printf("%p\n",p); //這里可以得到p的地址
return 0;
}
?1.5野指針:
? 1.5.1 什么是野指針:野指針就是指針指向的位置是不可知的(隨機的、不正確的、沒有明確限制的)
1.5.2野指針形成的原因:
<1>沒有初始化
#include<stdio.h>
int main()
{
int *p; //局部變量的指針沒有初始化,默認隨機值 這就是個野指針
return 0;
}
<2>數(shù)組的越界
#include<stdio.h>
int main()
{
int arr[5]={1,2,3,4,5}
int* p=arr;
for(int i=0;i<6;i++)
{
* (p++)=i;
}
return 0;
}
<3>指針指向的空間釋放
#include<stdio.h>
#include<stdlib.h>
int main()
{
int *p=(int*)malloc(40);
free(p);
return 0;
}
1.5.3如何避免野指針:
<1>. 指針初始化
二、指針的進階認識:
2.1字符指針:
#include<stdio.h>
int main()
{
char ch='m';
char *pr=&ch; //存放字符的指針
const char *pr1="hello xiaoma" //存放字符串的指針,他是存放字符傳的第一個地址并不是全部地址的存放.
//為什要加個const 要知道權(quán)限不能被擴大,只能被縮小,*pr1指向的是數(shù)組常量不能被改變所以用const來進行修飾。
printf("%c %s\n",*pr,pr1); //打印字符,和字符串
return 0;
}
2.2指針數(shù)組:
2.2.1:指針數(shù)組,重點在于數(shù)組,是用來存放指針的數(shù)組。
int* arr[10]; 存放整型指針的數(shù)組
double* arr1[10];存放double型指針的數(shù)組
char* arr[10] ; 存放字符型指針的數(shù)組
2.2.2指針數(shù)組的應(yīng)用,可以吧幾個一維數(shù)組合并成一個二維數(shù)組一樣。
#include<stdio.h>
int main()
{
int arr1[]={1,2,3,4};
int arr2[]={3,4,5,6};
int arr3[]={7,8,9,10};
int* arr[3]={arr1,arr2,arr3};
for(int i=0;i<3;i++)
{
for(int j=0;j<4;j++)
{
printf("%d ",arr[i][j]);
}
printf("\n");
}
return 0;
}
2.3數(shù)組指針:
2.3.1 數(shù)組指針,重點在于指針,他是指向數(shù)組的指針。
int arr[10]={0};
int *p=arr //這里表示p指向arr首元素的地址。這里是整型指針
int (*p1)[10]=&arr; //這里表示p1指向整個數(shù)組的地址 這是數(shù)組指針
2.3.2 數(shù)組指針的應(yīng)用:數(shù)組指針不怎么用在一維指針上大多是用在二維或者三維指針上
#include<stdio.h>
void print(int (*p)[3],int x,int y)
{
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
printf("%d ",*(*(p+i)+j)); //先對p解引用表示指向第一行的地址 加i就是指向第i行的地址 加j表示指向第j列的地址 最后在解引用就得到數(shù)值
}
printf("\n");
}
}
int main()
{
int arr[3][3]={1,2,3,2,3,4,3,4,5};
print(arr,3,3);
return 0;
}
2.4函數(shù)指針:
2.4.1通過數(shù)組指針我們類比函數(shù)指針,數(shù)組指針是指向數(shù)組的指針,那么函數(shù)指針呢,就是指向函數(shù)的指針。
int Add(int x,int y)
{
return x+y;
}
int (*p)(int,int)=&Add; //這就是定義一個函數(shù)指針p指向的就是Add函數(shù)的地址,沒錯函數(shù)也是有自己的地址的
2.4.2函數(shù)指針的簡單應(yīng)用:
#include<stdio.h>
int Add(int x,int y)
{
return x+y;
}
int Sub(int x,int y)
{
return x-y; // 這是為了我們更好的理解函數(shù)指針的應(yīng)用,所以寫的比較簡單。
}
int Mul(int x,int y)
{
return x*y;
}
int Div(int x,int y)
{
return x/y;
}
void Func(int (*p)(int ,int ),int x,int y)//傳的是函數(shù)指針
{
int ret = p(x,y);
printf("%d\n",ret);
} //可能覺得沒什么用 看一下復(fù)雜的應(yīng)用就知道指針函數(shù)的應(yīng)用
int main()
{
Func(Add,2,3);
Func(Sub,2,3);
Func(Mul,3,3); //這里就是一個函數(shù)來實現(xiàn)了加減乘除 而要一個函數(shù)實現(xiàn)四個函數(shù)的功能則需要運用函數(shù)指針
Func(Div,6,2);
return 0;
}
2.4.3函數(shù)指針的復(fù)雜應(yīng)用:
? ?~~回調(diào)函數(shù):回調(diào)函數(shù)就是一個通過函數(shù)指針調(diào)用的函數(shù)。如果你把函數(shù)的指針(地址)作為參數(shù)傳遞給另一個 函數(shù),當這個指針被用來調(diào)用其所指向的函數(shù)時,我們就說這是回調(diào)函數(shù)?;卣{(diào)函數(shù)不是由該函數(shù) 的實現(xiàn)方直接調(diào)用,而是在特定的事件或條件發(fā)生時由另外的一方調(diào)用的,用于對該事件或條件進 行響應(yīng)。
?????????我們上面實現(xiàn)的簡單應(yīng)用就是一個回調(diào)函數(shù),而現(xiàn)在我們要實現(xiàn)一個比較復(fù)雜的回調(diào)函數(shù):
qsort函數(shù),我們先去了解一下qsort函數(shù)怎么使用,這里我比較推薦一個網(wǎng)站就是專門用來查看c/c++庫函數(shù):https://legacy.cplusplus.com/https://legacy.cplusplus.com/這里我們來簡單的講述qsort函數(shù):qsort的函數(shù)是通過快排的方法來實現(xiàn)不同類型的排序問題,我們來通過代碼展示他的使用并且自己來實現(xiàn)一個qsort函數(shù)
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int swap(const void*p1,const void*p2)
{
return *(int*)p1-*(int*)p2;
}
int main()
{
int arr[10]={1,3,6,2,5,4,8,7,10,9};
int sz=sizeof(arr)/sizeof(arr[0]); //求數(shù)組的長度
qsort(arr,sz,sizeof(int),swap); //第一個要傳排序?qū)ο蟮牡刂?,然后排序的長度,寬度,最后排序的判斷方法。
for(int i=0;i<sz;i++)
{
printf("%d ",arr[i]);
}
return 0;
}
在用qsort按名字排一個結(jié)構(gòu)體:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
struct Student
{
char name[20];
int age ;
};
int swap(const void*p1,const void*p2)
{
return strcmp(((struct Student*)p1)->name,((struct Student*)p2)->name);
}
int main()
{
struct Student arr[]={{"xiaomma",18},{"lisi",17},{"wanger",20}};
int sz=sizeof(arr)/sizeof(arr[0]);
qsort(arr,sz,sizeof(struct Student),swap);
for(int i=0;i<sz;i++)
{
printf("%s\n",arr[i].name);
}
return 0;
}
創(chuàng)建自己的qsort函數(shù)m_qsort :
這里m_qsort我用的是冒泡法,雖然效率低了,但是我們要掌握的是函數(shù)指針的用法!
void Swap(char*buf1,char*buf2,int width){ int i=0; for(i=0;i<width;i++) //進行位置的交換 { char tmp=*buf1; *buf1=*buf2; *buf2=tmp; buf1++; buf2++; } } //這里是實現(xiàn)和qsort一樣的功能不過我使用的冒泡的形式來實現(xiàn)的 void bubble_sort(void* base ,int sz,int width,int (*cmp)(const void*e1,const void*e2)) { int i=0; int j=0; for(i=0;i<sz-1;i++) { for(j=0;j<sz-i-1;j++) { if(cmp((char*)base+j*width,(char*)base+(j+1)*width)>0) { Swap ((char*)base+j*width,(char*)base+(j+1)*width,width); //因為比較類型不同所以用char傳地址比較好,char才占一個地址,我們知道總長度也知道寬度就好進行交哈。 } } } } int cmp_int(const void* e1,const void*e2) { return (*(int *)e1-*(int *)e2); } int main() { int arr[]={9,8,7,6,5,4,3,2,1,0}; int sz=sizeof(arr)/sizeof(arr[0]); bubble_sort(arr,sz,sizeof(arr[0]),cmp_int); for(int i=0;i<sz;i++) { printf("%d ",arr[i]); } return 0; }
? 代碼很長但很有必要自己來實現(xiàn)一下就能夠深入的理解函數(shù)指針存在的意義啦,如果要有不理解的地方可以直接問我的。^?_?^
2.5函數(shù)指針數(shù)組:
? ? ? ?2.5.1函數(shù)指針數(shù)組也就是存放函數(shù)指針的數(shù)組。
? ??
int Add(int x,int y)
{
return x+y;
}
int (*p)(int ,int )=&Add //函數(shù)指針
int (*arr[4])(int,int ); //函數(shù)指針數(shù)組 //通過對比我們就很容易發(fā)現(xiàn)就是把p換成一個數(shù)組 他的類型就是函數(shù)指針數(shù)組
int (*(*prr)[5])(int ,int )//函數(shù)指針數(shù)組的指針。哈哈哈哈類似于套娃是的 就是便于大家取了解這個東西
? 2.5.2函數(shù)指針數(shù)組的應(yīng)用:也是很容易的可以把我們上面寫的四個功能用一遍
#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 i=0;
int (*arr[])(int ,int )={Add,Sub,Mul,Div};
for(i=0;i<4;i++)
{
printf("%d\n",arr[i](6,2));
}
return 0;
}
?總結(jié):
1、從指針的初級指針是什么,和如何使用到指針的進階一大堆不同的指針,這里小馬都已經(jīng)全部寫完,還有一個結(jié)構(gòu)體指針,我覺得看過我的鏈表就應(yīng)該很容易的掌握,這里我都不進行寫啦,我覺得比較難的點就在于函數(shù)指針這里的qsort函數(shù)自己的實現(xiàn),我認為很有必要多看幾遍自己在寫一遍,才能深入理解qsort函數(shù),和函數(shù)指針。文章來源:http://www.zghlxwxcb.cn/news/detail-402169.html
2、最后碼文不易,如果覺得文章有幫助的話,請多多關(guān)注,希望我們能夠一同進步,共同發(fā)展?。。?!^?_?^文章來源地址http://www.zghlxwxcb.cn/news/detail-402169.html
到了這里,關(guān)于c語言指針(深入了解指針)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!