C語言的靈魂—指針
指針是什么
在計算機(jī)科學(xué)中腮敌,指針(Pointer)是編程語言中的一個對象膜钓,利用地址桃煎,它的值直接指向(points to)存在電腦存儲器中另一個地方的值零蓉。由于通過地址能找到所需的變量單元笤受,可以說,地址指向該變量單元敌蜂。因此箩兽,將地址形象化的稱為“指針”≌潞恚總結(jié)來說汗贫,指針就是指向地址的變量!
指針的作用
c語言指針可以有效地表示復(fù)雜的數(shù)據(jù)結(jié)構(gòu)秸脱、動態(tài)分配內(nèi)存落包、高效地使用數(shù)組和字符串、使得調(diào)用函數(shù)時得到多個返回值等摊唇。指針的應(yīng)用往往與數(shù)組聯(lián)系在一起妥色,是最頻繁的,也是最基礎(chǔ)的遏片。參數(shù)傳遞時只需要拷貝地址值嘹害,提高程序的運(yùn)行效率撮竿。有效的表示數(shù)據(jù)結(jié)構(gòu),能動態(tài)分配內(nèi)存笔呀。
指針
指針的語法
指針變量的定義: 類型 * 指針變量名
&:表示取地址操作
*: 表示取地址中的值
怎么去理解指針
大家可能一時半會可能很難理解指針含義幢踏。我們的計算機(jī)都會有一個內(nèi)存,并且這個內(nèi)存的每一個部分有一個標(biāo)記表示它的位置许师,這個標(biāo)識就是我們的地址房蝉,地址對應(yīng)的區(qū)域存放的就是我們的數(shù)據(jù)(值)。就像我們住酒店微渠,酒店是內(nèi)存搭幻,門牌號是我們的地址,住在房間里的人就是我們的數(shù)據(jù)逞盆!
代碼示例
#include<stdio.h>
int main(){
int num = 10;
double num2 = 10.0;
int * p ;
p = #
//這種不同類型的變量之前的操作是不合法的
// p = &num2;
printf("p = %p\n",p);
printf("num = %d\n",num);
printf("*p = %d\n",*p);
// num 和 p代表的是同一個地址的數(shù)據(jù)檀蹋,
// 當(dāng)使用 *p 去修改數(shù)據(jù)的時候,num代表的數(shù)據(jù)也會改變云芦!
*p = 11;
printf("p = %p\n",p);
printf("num = %d\n",num);
printf("*p = %d\n",*p);
return 0;
}
/*
運(yùn)行結(jié)果:
p = 0x7ffee1eee7c8
num = 10
*p = 10
p = 0x7ffee1eee7c8
num = 11
*p = 11
*/
通過以上代碼我們不難理解:指針變量中俯逾,p 存放的是地址,p 是取地址對應(yīng)的值舅逸。num 變量直接存放地址對應(yīng)的值桌肴!當(dāng)我們使用 *p 修改數(shù)據(jù)的時候,我們 num 的存放的值也會發(fā)生改變琉历!我們使用 & 符號即可取出變量的地址
舉個例子坠七,p 存放的是門牌號,p 代表居住的客人旗笔,num 也是代表這個門牌號下居住的客人彪置,當(dāng)使用 *p 修改掉居住的人,num 也會發(fā)生相應(yīng)的改變换团,因為他們代表的都是這個門牌號下居住的人悉稠。&num 即代表取出這個客人的房間門牌號
什么是雙重(n重)指針
我們根據(jù)之前的解釋可以知道,每個變量在內(nèi)存中都有一個地址相對應(yīng)艘包。雙重指針實際上存放的全是地址的猛。
代碼示例
#include<stdio.h>
int main(){
int num = 10;
int * p;
p = #
// 雙重指針
int ** q;
// 指針變量也是變量的一種,即 p 也是有對應(yīng)的地址
// &p 即取 p 變量的地址
q = &p;
// p 變量存放的地址 想虎,即num變量的地址
printf("p = %p\n",p);
// p 變量自身的地址
printf("p = %p\n",&p);
// q 存放的地址就是 p 變量自身的地址
printf("q = %p\n",q);
// *p == num
printf("*p = %d\n",*p);
// **q == *p == num
printf("**q = %d\n",*p);
return 0;
}
/*
執(zhí)行結(jié)果:
p = 0x7ffee910c7c8
p = 0x7ffee910c7c0
q = 0x7ffee910c7c0
*p = 10
**q = 10
*/
圖解
graph LR
q --> p
p --> num
n重指針
n重指針同理
數(shù)組實際上使用的就是指針卦尊,我們再學(xué)習(xí)下數(shù)組類型
指針函數(shù)和函數(shù)指針
指針函數(shù)
顧名思義,指針函數(shù)就是返回值為指針的函數(shù)
語法示例
#include <stdio.h>
int *fun(int a, int b, int *p)
{
*p = a + b;
return p;
}
int main()
{
int *p;
p = fun(10, 10, p);
printf("%d \n", *p);
return 0;
}
/*
執(zhí)行結(jié)果:
20
*/
函數(shù)指針
函數(shù)指針就是指向函數(shù)的指針舌厨。一個函數(shù)標(biāo)識符就表示了它的地址
示例代碼
#include <stdio.h>
int add(int a, int b)
{
return a + b;
}
int sub(int a, int b)
{
return a - b;
}
int (*fun)(int a, int b);
int main()
{
// 函數(shù)指針用法一
fun = add;
//調(diào)用方法二
printf("%d \n", fun(10, 10));
//用法二
fun = ⊂
//調(diào)用方法一
printf("%d \n", (*fun)(10, 10));
return 0;
}
/*
執(zhí)行結(jié)果:
20
0
*/
一維數(shù)組
語法規(guī)則
類型名 變量名 [數(shù)組大小]
字符串?dāng)?shù)組:C語言中一個字符串的界定范圍是 '\0',當(dāng)遇到'\0'時認(rèn)為字符串已經(jīng)結(jié)束
語法示例
#include<stdio.h>
int main(){
char chs[100] = {'a','b','c','\0'};
printf("chs = %s\n",chs);
//指針版示例
printf("point verion:\n");
printf("chs = ");
for(int i = 0; *(chs + i) != '\0';i ++){
printf("%c",*(chs + i));
}
printf("\n");
return 0;
}
/*
運(yùn)行結(jié)果:
chs = abc
point verion:
chs = abc
*/
我們從示例代碼中可以看到: chs[i] 等價于 * (chs + i)
二位數(shù)組
語法定義
類型名 數(shù)組變量名稱 [行數(shù)][列數(shù)]
代碼示例
#include <stdio.h>
int main()
{
//未初始化的數(shù)組其值是不確定的
int arr[7][7] = {0};
//輸入行數(shù)
printf("%lu\n", sizeof(arr) / sizeof(arr[0]));
//輸出列數(shù)
printf("%lu\n", sizeof(arr[0]) / sizeof(int));
//打印數(shù)組信息 數(shù)組實際上就是二維指針
for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
{
for (int j = 0; j < sizeof(arr[0]) / sizeof(int); j++)
{
printf("%d ", (*(arr + i) + j));
}
printf("\n");
}
// 打印數(shù)組的地址信息 可以看到岂却,數(shù)組實際上是一塊連續(xù)的地址空間
for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
{
for (int j = 0; j < sizeof(arr[0]) / sizeof(int); j++)
{
printf("%p ", (*(arr + i) + j));
}
printf("\n");
}
return 0;
}
/*
執(zhí)行結(jié)果:
7
7
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0x7ffee5a9d700 0x7ffee5a9d704 0x7ffee5a9d708 0x7ffee5a9d70c 0x7ffee5a9d710 0x7ffee5a9d714 0x7ffee5a9d718
0x7ffee5a9d71c 0x7ffee5a9d720 0x7ffee5a9d724 0x7ffee5a9d728 0x7ffee5a9d72c 0x7ffee5a9d730 0x7ffee5a9d734
0x7ffee5a9d738 0x7ffee5a9d73c 0x7ffee5a9d740 0x7ffee5a9d744 0x7ffee5a9d748 0x7ffee5a9d74c 0x7ffee5a9d750
0x7ffee5a9d754 0x7ffee5a9d758 0x7ffee5a9d75c 0x7ffee5a9d760 0x7ffee5a9d764 0x7ffee5a9d768 0x7ffee5a9d76c
0x7ffee5a9d770 0x7ffee5a9d774 0x7ffee5a9d778 0x7ffee5a9d77c 0x7ffee5a9d780 0x7ffee5a9d784 0x7ffee5a9d788
0x7ffee5a9d78c 0x7ffee5a9d790 0x7ffee5a9d794 0x7ffee5a9d798 0x7ffee5a9d79c 0x7ffee5a9d7a0 0x7ffee5a9d7a4
0x7ffee5a9d7a8 0x7ffee5a9d7ac 0x7ffee5a9d7b0 0x7ffee5a9d7b4 0x7ffee5a9d7b8 0x7ffee5a9d7bc 0x7ffee5a9d7c0
*/
數(shù)組相關(guān)的函數(shù)
#include <stdio.h>
int main(){
char old[100];
char new[200];
int n = 10;
//字符數(shù)組操作函數(shù)
//將舊數(shù)組的數(shù)據(jù)拷貝到的新的數(shù)組之中。舊數(shù)組的數(shù)據(jù)遇到了\0就停止復(fù)制。新數(shù)組的長度必須大于等于舊數(shù)組數(shù)據(jù)長度 + 1
strcpy(new,old);
?// 將舊數(shù)組的前n位字符拷貝到新數(shù)組中躏哩。新數(shù)組的長度必須大于等于新數(shù)組原數(shù)據(jù)長度 + 舊數(shù)組數(shù)據(jù)長度 + 1
strncpy(new,old,n);
//兩個字符數(shù)組進(jìn)行比較署浩。首先從第一位開始逐位比較,按照字典序的大小進(jìn)行比較扫尺。遇到第一個不等的字符或者遇到了\0停止比較筋栋。等于返回0,new < old返回 -1正驻,new > old 返回 1
strcmp(new,old);
//將兩個字符串進(jìn)行連接弊攘。新數(shù)組的長度必須大于等于 新數(shù)組的數(shù)據(jù)長度 + 舊數(shù)組的數(shù)據(jù)長度 + 1
strcat(new,old);
return 0;
}
以上就是本期的全部內(nèi)容了,感謝你能看到這里姑曙。我們下期見襟交!