C語言指針
- 為什麼使用指針?
- 指針的定義
- 指向數組的指針
- 指針的通路
- 通路指針所指向的内容
- 空指針
-
-
- 1、空指針
- 2、空指針的使用
- 壞指針
-
- 指針的算數運算(指針的自增、指針的自減、指針與整數的加減)
-
-
- 指針自加
- 指針自減
- 指針與整數加減
- 指針與指針之間的加減運算
-
- const 修飾
- 二級指針
- 函數指針
-
-
- 函數二級指針
- 數組和指針的糾纏
-
- 指針數組
-
-
- 指針和多元數組
-
- void類型的指針
- 函數指針
- 函數傳回值
任何類型指針所占空間是4個位元組,在計算機架構中最大的尋址範圍為4個位元組
為什麼使用指針?
前言: 不使用指針也可以建構起軟體,帶着疑問往下看
- 函數的值傳遞,無法通過調用函數,來修改函數的實參
- 被調用函數需要提供更多的“傳回值”給調用函數
- 減少值傳遞時帶來的額外開銷,提高代碼執行效率
指針的定義
(跑了聊和尚跑不了廟:和尚是跑了但是,我們知道寺廟的位址,還是可以去寺廟找到那個和尚)
(買東西寄快遞,隻要給個位址,就可以收到快遞)
#include <stdio.h>
#include <Windows.h>
int main( void )
{
int age;
/*
** 定義了一個指針
** 指針本身也是一個變量
** 名稱是p,他是一個指針,可以指向一個整數
** p的值是一個整數的位址
*/
int *p;
/*
** p指向了age
** p的值就是age的位址
*/
p = &age;
/*
scanf_s("%d", &age);
*/
scanf_s("%d", p);
printf("age:%d \n", age);
system("pause");
return 0;
}

#include <stdio.h>
#include <time.h>
#include <Windows.h>
/*************************************************
** 1、函數的值傳遞,無法通過調用函數,來修改函數的實參
** 2、被調用函數需要提供更多的“傳回值”給調用函數
** 3、減少值傳遞時帶來的額外開銷,提高代碼執行效率
**************************************************/
/*給英雄加血的函數*/
void add_blood1( int blood )
{
blood += 1000;
}
bool add_blood3( int blood )
{
if ( blood >= 1000 )
{
return false;
}
else
{
blood+=1000;
}
return true;
}
int add_blood2( int blood )
{
blood += 1000;
return blood;
}
/*減少值傳遞時帶來的額外開銷,提高代碼執行效率*/
struct _hexo_stat
{
int blood; //英雄血量
int power; //英雄攻擊力
int level; //英雄級别
char name[64]; //英雄名字
char details[1024]; //描述英雄狀态
};
struct _hexo_stat upgrade1(struct _hexo_stat hexo, int type)
{
switch(type)
{
case 1:
hexo.blood += 1000;
hexo.power += 30;
hexo.level++;
break;
case 2:
hexo.blood += 2000;
hexo.power += 50;
hexo.level++;
break;
default:
break;
}
return (hexo);
}
/*指針版本*/
void upgrade2(struct _hexo_stat *hexo, int type)
{
switch(type)
{
case 1:
hexo->blood += 1000;
hexo->power += 30;
hexo->level++;
break;
case 2:
hexo->blood += 2000;
hexo->power += 50;
hexo->level++;
break;
default:
break;
}
}
int main( void )
{
time_t start, end;
struct _hexo_stat hexo_xiaohei;
strcpy(hexo_xiaohei.name, "小黑");
hexo_xiaohei.blood = 100;
hexo_xiaohei.power = 10;
hexo_xiaohei.level = 1000;
time(&start); /*1970年1月1日0時0分0秒 至今的秒數*/
for(int i=0; i < 99999999; i++)
{
/*
upgrade1(hexo_xiaohei, 1);
*/
upgrade2(&hexo_xiaohei, 2);
}
time(&end);
printf("小黑的血量:%d \n", hexo_xiaohei.power);
printf("%d \n", end-start);
/*英雄小黑本身的血量*/
//int hexo_xiaohei = 1000;
/*加血*/
//add_blood1(hexo_xiaohei);
//hexo_xiaohei = add_blood3(hexo_xiaohei);
/*加血後的結果*/
/*
printf("hexo_xiaohei is blood :%d \n", hexo_xiaohei);
*/
system("pause");
return 0;
}
指向數組的指針
指針的初始化
#include <stdio.h>
#include <Windows.h>
int main( void )
{
int room = 900;
int *p1 = &room1;
int *p2 = &room1;
printf("room1的位址是:0x%p \n",&room);
printf("p1的位址是:0x%p \n",&p1);
printf("p2的位址是:0x%p \n",&p2);
/*
** 整型指針,所占位元組數,在32位的系統裡 尋址是 4個位元組數
** 在64位的系統裡 尋址是 8個位元組數
*/
printf("room1所占位元組是:%d \n",sizeof(room));
printf("p1所占位元組是:%d \n",sizeof(p1));
printf("p2所占位元組是:%d \n",sizeof(p2));
system("pause");
return 0;
}
指針的通路
通路指針
#include <stdio.h>
#include <Windows.h>
int main(void)
{
/*
** 指針也是一個變量
** 1. 通路指針本身
** 2.
** 通路(讀、寫)指針本身的值,和其他普通變量的通路方式相同
**
**
*/
int room = 2;
int *p1 = &room;
int *p2 = p1;
printf("room的位址:%d\n",&room);
printf("p1的值:%d p2的值:%d\n", p1, p2);
int *p3 = p1;
printf("p3的值:%d\n",p3);
p3 = &room;
printf("p3的值:%d room的位址:%d \n", p3, &room);
/*
** 使用16進制列印,把位址當成一個無符号數來處理
**
*/
printf("p1=0x%p\n", p1);
printf("p1=0x%x\n", p1);
printf("p1=0x%X\n", p1);
system("pause");
return 0;
}
通路指針所指向的内容
1、間接通路符(解引符)“ * ” 是一個特殊的運算符,girl表示讀取指針girl所指向的變量
** 2、帶個 “*” 就等同于間接地通路這個位址指向變量的值(的内容)*
#include <stdio.h>
#include <Windows.h>
int main(void)
{
/*
** 指針也是一個變量
** 1. 通路指針本身
** 2.
** 通路(讀、寫)指針本身的值,和其他普通變量的通路方式相同
**
**
*/
int room = 2;
int * girl = &room;
room = 3;
int x;
x = *girl; /* 間接通路符(解引符)“ * ” 是一個特殊的運算符,*girl表示讀取指針girl所指向的變量*/
printf("x:%d\n",x);
*girl = 4;
printf("room:%d *girl:%d\n", room, *girl);
/* 帶個 "*" 就等同于間接地通路這個位址指向變量的值(的内容)*/
system("pause");
return 0;
}
空指針
1、空指針
空指針就是值為,0 的指針。(任何資料都不會儲存在位址為0的記憶體中,它是作業系統預留的記憶體塊)
int p = 0;
或者
int p = NULL; //建議使用這種
2、空指針的使用
1、指針初始化為空指針
int *select = NULL;
目的是避免資料非法通路
2、指針不再使用時,可以設定為空指針
int *select = &pointer;
//不再使用了
select = NULL;
3、表示這個指針還沒有具體的指向,使用前進行合法性的判斷
#include <stdio.h>
#include <Windows.h>
int main(void)
{
//int *p = NULL;
//if(p){ //p等同于p!=NULL
//指針不為空,對指針進行操作
//}
int *p = NULL;
int pointer_p;
p = &pointer_p;
if(p!=NULL)
{
printf(" *p的值不為空 \n");
}
system("pause");
return 0;
}
壞指針
int *select; //指針沒有初始化
形式一
printf(“選擇的房間是:%d\n”, *select);
形式二
select = 100;
printf(“選擇的房間是:%d\n”,select);
指針的算數運算(指針的自增、指針的自減、指針與整數的加減)
指針自加
#include <stdio.h>
#include <Windows.h>
int main(void)
{
int age[] = {21, 15, 18, 14, 23, 28, 10};
int len = sizeof(age)/sizeof(age[0]); /*計算age數組的長度*/
for( int i = 0; i < len; i++ )
{
printf("第%d學員的年齡是:%d\n", i+1, age[i]);
}
/*
** 數組本身的位址和數組第一個元素的位址是相同的
** 1、列印數組的位址
** 2、列印數組第一個元素的位址
*/
printf("age的位址:%d age[0]第一個元素的位址:%p\n",age, &age[0]);
int *p = age;
/*通路第一個元素*/
printf("數組的第一個元素:%d\n", *p);
/*通路第二個元素*/
//p = p+1; /* p = p + 1*(sizeof(int)) */
//printf("數組的第二個元素:%d p的位址是:0x%p\n", *p, p);
for( int i = 0; i < len; i++ )
{
printf("第%d學院的年齡:%d 位址:0x%p \n",i+1, *p, p);
p++;
}
printf("---------------------------\n");
char ch[4] = {'a', 'b', 'c', 'd'};
int len_ch = sizeof(ch)/sizeof(char);
char *cp = ch;
for(int i = 0; i < len_ch; i++)
{
printf("第%d個元素的值:%c 位址是:0x%p\n",
i+1, *cp, cp);
cp++;
}
system("pause");
return 0;
}
指針自減
輸入字元串,逆轉輸出
#include <stdio.h>
#include <string>
#include <Windows.h>
/*
** 輸入字元串進行,逆轉輸出
*/
int main(void)
{
char input[128];
int len;
char tmp;
scanf_s("%s", input, 128);
len = strlen(input);
for( int i = 0; i < len/2; i++)
{
tmp = input[0];
input[i] = input[len-i-1];
input[len-i-1] = tmp;
}
/*第一種方法*/
for( int i = 0; i < len; i++)
{
printf("%c", input[i]);
}
printf("\n");
printf("逆轉後:%s", input);
/*第二種方法*/
for( int i = 0; i < len; i++)
{
printf("%c", input[len-i-1]);
}
printf("\n");
/*第三種方法*/
char *p = &input[len-1];
for( int i = 0; i < len; i++)
{
printf("%c", *p--);
//p--;
}
printf("\n");
system("pause");
return 0;
}
指針與整數加減
指針與整數的加減在數組中,在數組元素中表示元素向前移動一位或向後移動一位(資料類型 (int) p基位址 + n * sizeof(資料類型) )
#include <stdio.h>
#include <string>
#include <Windows.h>
int main(void)
{
int ages[] = {10,2,3,4,5,61,90,8,9,10};
int len = sizeof(ages) / sizeof(ages[0]);
int *p1 = ages;
printf("第一個人的年齡:%d\n", *p1 + 6); /* 優先級(*p)+6 */
printf("第二個人的年齡:%d\n", *(p1 + 6));
int *p2 = &ages[4];
printf("第二個人前一個人的年齡:%d\n",*(p2 - 1));
printf("第二個人前三個人的年齡:%d\n",*(p2 - 3));
system("pause");
return 0;
}
指針與指針之間的加減運算
指針與指針之間不能進行相加操作?
#include <stdio.h>
#include <string>
#include <Windows.h>
int main(void)
{
int ages[] = {10,2,3,4,5,6,4,8,9,10};
int len = sizeof(ages) / sizeof(ages[0]);
int *xiao_cheng = ages+6;
int *xiao_zhang = ages+7;
printf("xiao_zhang - xiao_cheng = %d\n",
*xiao_zhang - *xiao_cheng);
printf("xiao_zhang - xiao_cheng = %d\n",
xiao_zhang - xiao_cheng);
/*//指針之間不能相加
printf("xiao_zhang + xiao_cheng = %d\n",
xiao_zhang + xiao_cheng);
*/
system("pause");
return 0;
}
const 修飾
const 關鍵字 隻讀。const 離類型(int) 近,還是離指針變量名近,離誰近,就修飾誰,誰就不能變
#include <stdio.h>
#include <string>
#include <Windows.h>
/*
** const 關鍵字 隻讀
** const 離類型(int) 近,還是離指針變量名近,離誰近,就修飾誰,誰就不能變
*/
int main(void)
{
int wife = 24;
int girl = 18;
/*
** 渣男 随心所欲 沒有什麼限制
*/
int * zha_man = &wife;
* zha_man = 29;
zha_man = &girl;
* zha_man = 19;
printf("wife:%d girl:%d\n", wife, girl);
/*
** 直男 以自我為中心
*/
/* const修飾後 使用指針通路時 隻能讀 不能修改 */
/* const int * zhi_man = &wife; */ //第一種 寫法
int const * zhi_man = &wife; //第二種 寫法
/*
//不能給常量指派
* zhi_man = 20;
*/
zhi_man = &girl;
printf("wife:%d girl:%d\n", wife, girl);
/*
** 暖男 終此一生
*/
int * const nuan_man = &wife;
/* nuan_man = &girl; */
printf("wife: %d\n",wife);
/*
** 超級暖男 一切宜順老婆 聽老婆的
*/
//既不能修改 所指向的 位址,也不能修改,裡面的值
const int * const super_nuan_man = &wife;
printf("wife:%d\n",wife);
system("pause");
return 0;
}
二級指針
一級指針:裡儲存的是普通變量的位址
二級指針:裡儲存的是另一個指針變量的位址
#include <stdio.h>
#include <Windows.h>
int main(void)
{
int guizi2 = 888; //存手槍的第二個櫃子
int * guizi1 = &guizi2; //存第二個櫃子位址的 第一個櫃子
int ** liu_jian = &guizi1;//手握第一個櫃子位址的 劉健
printf("劉健手握第一個櫃子的位址:0x%p\n",*liu_jian);
printf("劉健從第一個櫃子拿到第二個櫃子的位址:0x%p\n",&guizi2);
int *tmp;
tmp = &guizi2;
//printf("劉健從第一個櫃子拿到第二個櫃子的位址,打開櫃子取出槍:%d\n",*(*liu_jian));
printf("劉健從第一個櫃子拿到第二個櫃子的位址,打開櫃子取出槍:%d\n",*tmp);
system("pause");
return 0;
}
函數指針
#include <stdio.h>
#include <Windows.h>
/*一級指針*/
void swap(int *a, int *b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
int main(void)
{
int x = 100, y = 1000;
swap(&x , &y);
printf("x=%d ,y=%d\n",x,y);
system("pause");
return 0;
}
函數二級指針
二級指針可以将 參數 帶入函數 ,也可以将函數 裡的參數帶出
#include <stdio.h>
#include <Windows.h>
void boy_home(int **meipo) //局部變量,函數結束,一起銷毀
{
static int boy = 23;
*meipo = &boy;
}
int main(void)
{
int *meipo = NULL;
boy_home(&meipo); //main裡的 *meipo 0x666
printf("boy: %d\n",*meipo);
system("pause");
return 0;
}
數組和指針的糾纏
#include <stdio.h>
#include <Windows.h>
//數組标表示
void array_pointer1(int days[], int len)
{
printf("====================================== \n");
for (int i = 0; i < len; i++)
{
printf("第 %2d 月的最後一天是 %d \n", i + 1, days[i]);
}
}
//指針表示
void array_pointer2(int days[], int len)
{
printf("====================================== \n");
for (int i = 0; i < len; i++)
{
printf("第 %2d 月的最後一天是 %d \n", i + 1, *(days + i));
}
}
int main(void)
{
int days[12] = {31, 28, 32, 30, 31, 28, 31, 31, 28, 31, 31, 28};
int len = sizeof(days) / sizeof(days[0]);
/*
for (int index = 0; index < len; index++)
{
printf("第 %2d 個月的最後一天是 %d \n", index+1, *(days+index));
}
*/
array_pointer1(days, LEN);
array_pointer2(days, LEN);
system("pause");
return 0;
}
指針數組
#include <stdio.h>
#include <Windows.h>
int main(void)
{
int girls[4][3] = { {178, 179, 167},
{135, 167, 157},
{176, 166, 190},
{155, 165, 180}};
int *qishou[2]; //定義一個有兩個元素的指針數組,每個元素都是指針變量
if (girls[0][0] > girls[0][1]) // 如果 178 > 179
{
qishou[0] = &girls[0][0]; //把 第零個元素(178)位址 給 第一個旗手
qishou[1] = &girls[0][1]; //把 第一個元素(179)位址 給 第二個旗手
}
else //否則
{
qishou[0] = &girls[0][1]; //把 第一個元素(179)位址 給 第一個旗手
qishou[1] = &girls[0][0]; //把 第零個元素(178)位址 給 第二個旗手
}
for (int index = 2; index < 12; index++) //
{
if (*qishou[1] >= girls[index / 3][index % 3]) //如果 179 大于 girls[0][2]
{
continue;
}
if (girls[index / 3][index % 3] <= *qishou[0]) // 如果176 小于 178 就把 176 給 棋手 二
{
qishou[1] = &girls[index / 3][index % 3];
}
else //否則 就把 178 給棋手二 把 179 給棋手一
{
qishou[1] = qishou[0];
qishou[0] = &girls[index / 3][index % 3];
}
}
printf("最高的是:%d , 次高的是:%d \n", *qishou[0], *qishou[1]);
system("pause");
return 0;
}
指針和多元數組
#include <stdio.h>
#include <Windows.h>
int main(void)
{
int A_302[4][3] = { {1, 2, 3},
{4, 5, 6},
{7, 18, 9},
{10, 11, 12}};
int (*p)[3];
int* boy = NULL;
p = &A_302[0];
/*for (int i = 0;i < 4;i++)
{
for (int j = 0;j < 3;j++)
{
printf("%d ", (*p)[j]);
}
printf("\n");
p++;
}*/
boy = &(*p)[0];
for (int i = 0;i < 4;i++)
{
for (int j = 0;j < 3;j++)
{
printf("%d ", *((*p)+j));
if (*boy < *((*p) + j))
{
boy = (*p) + j;
}
}
printf("\n");
p++;
}
printf("偷窺的人是:%d \n", *boy);
return 0;
}
void類型的指針
所有其它類型的指針都可以隐式自動轉換成void類型
#include <stdio.h>
#include <Windows.h>
int main(void)
{
int arr[] = {1, 2, 3, 4, 5};
char ch = 'a';
void * p = arr; //定義了一個void類型的指針
//p++; //void * 指針不允許進行算術運算
p = &ch; //其它類型都可以自動轉換成void * 指針
//所有其它類型的指針都可以隐式自動轉換成void類型
printf("p:0x%p \nch:0x%p \n",p ,&ch);
//強制類型轉換
char * p1 = (char *)p;
printf("%c \n", *p1);
system("pause");
return 0;
}
函數指針
#include <stdio.h>
#include <Windows.h>
int compare_int(const void * a, const void * b)
{
printf("已經調用了 compare_int 哦\n");
int * p1 = (int *)a;
int * p2 = (int *)b;
//printf("a的位址:0x%p \nb的位址:0x%p\n",&a,&b);
return *p1 - *p2;
}
int compare_char(const void * a, const void * b)
{
printf("已經調用了 compare_int 哦\n");
char ch1 = *((char *) a);
char ch2 = *((char *) b);
if(ch1 >= 'A' && ch1 <= 'Z')
{
ch1 += 32;
}
if(ch2 >= 'A' && ch2 <= 'Z')
{
ch2 += 32;
}
//printf("a的位址:0x%p \nb的位址:0x%p\n",&a,&b);
return ch1 - ch2;
}
int main1(void)
{
int x = 10;
int y = 5;
//函數指針的定義 把函數聲明移過來,把函數名改成(* 函數指針名)
int (*fp)(const void *, const void *);
fp = &compare_int;
(*fp)(&x,&y);
fp(&x,&y);
printf("compare_int 的位址:0x%p\n",&compare_int);
compare_int(&x, &y);
system("pause");
return 0;
}
int main(void)
{
//對整形數組排序
int arr1[] = {2, 5, 1, 22, 2124, 2321, 3, 9, 10};
qsort(arr1, sizeof(arr1)/sizeof(int), sizeof(int), &compare_int);
for(int i = 0; i < sizeof(arr1)/sizeof(int);i++)
{
printf("%d \n", arr1[i]);
}
//qsort 可以對任何類型的數組進行排序
char arr2[] = {"abcdefgABCDEFGHI"};
qsort(arr2, sizeof(arr2)/sizeof(char)-1, sizeof(char), &compare_char);
for(int i = 0; i < sizeof(arr2)/sizeof(char)-1;i++)
{
printf(" %c ",arr2[i]);
}
printf("\n");
system("pause");
return 0;
}
函數傳回值
#include <stdio.h>
#include <Windows.h>
#include <iostream>
using namespace std;
int add(int x, int y)
{
int sum = x + y;
return sum;
}
int * add1(int x, int y)
{
int sum = x + y;
return ∑
}
int * add2(int x, int y)
{
int * sum = NULL;
sum = new int;
*sum = x + y;
return sum;
}
int * add3(int x, int y)
{
static int sum = 0;
cout << "sum:%d"<< sum <<endl;
sum = x + y;
return ∑
}
int main(void)
{
int a = 3;
int b = 5;
int * sum = NULL;
//sum = add1(a,b);
//add2(a,b);
//cout << add1(a,b) << endl;
//cout << *sum << endl;
//cout << *(add2(a,b)) << endl;
//delete sum;
//不能使用外部函數局部變量的位址
sum = add3(a,b);
cout << *sum << endl;
* sum = 888;
add3(a,b);
system("pause");
return 0;
}