一 概念
前言:指針變量就是變量,指針就是地址。
首先考慮四個問題:指針變量的類型,指針所指向的類型,指針的值或是指針所指的地址,指針本身所佔據的內存區。
Int *p;
1, 指針類型: Int *p;//指針p的類型即爲 int *
2, 指針所指向的類型: Int *p;//指針p指向的類型爲int,也就是指針指向的內存區的類型
3, 指針的值(= 指針所指向的內存地址):指針指向的變量的首址,指針所指向的類型決定接下來多少個地址裏存的值爲指針所指向的值。
Ps:遇到一個指針,立刻想到:這個指針的類型是什麼?指針指的類型是什麼?該指針指向了哪裏?
4, 指針本身所佔據的內存區:用函數sizeof(指針的類型)檢測(例:int k = sizeof(int *))
二 示例說明
示例1:訪問指針的指向的內容,也就是地址p的內容
char c[16] = "i am a student";
int main() {
char* p = c; //數組名c表示該數組的始址,將c值賦給char*型的指針p
for(int i = 0; i < 16; ++i) {
printf("%c", *p); //*p:表示訪問地址爲p的內存區的內容
p++; //內存區地址移動
}
//Output: i am a student
}
示例2:指針的強制類型轉換
char c[16] = "i am a student";
int main() {
int* p = (int*) c; //類型轉換,指針所指向類型應一致
for(int i = 0; i < 16; ++i) {
printf("%c", *p); //*p:表示訪問地址爲p的內存區內容
p++; //指針c+1,移動一個位置,而p+1,移動四個位置
//指針所指向類型不同,佔據的內存單元數不同
}
//Output: i " " t n
}
int a[16] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
int main() {
char* p = (char*) a;
for(int i = 0; i < 8; ++i) {
printf("%d\n", *p); //*p:表示訪問地址爲p的內存區內容,內容+1
p += 4; //p+4,移動到下一個數組位置(類型不同)
}
//Output: 1 1 1 1
}
示例3:遍歷數組,更改內容
int a[16] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
int main() {
int* p = a;
for(int i = 0; i < 8; ++i) {
printf("%d", ++(*p)); //*p:表示訪問地址爲p的內存區內容,內容+1
p++; //p+1,移動到下一個數組位置
}
//Output: 2 2 2 2
}
示例4:一級指針和二級指針
int a[16] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
int* p = a; //先定義指針,a能表是地址,但不是指針
int** pt = &p; //指針pt類型int**,指向int*(存放的是地址)
//pt指向的是指針p的內容,pt即是指針p的地址
示例5:字符串指針(整型指針指向一個數,串指針指向一整個串,且均可按下標訪問)
char c[16] = "i am a student";
int main() {
char* p = c;
printf("%s\n", p); //輸出整個字符串
printf("%c\n", *(p + 2)); //輸出“a”字符
}
示例6:結構體指針
struct Node
{
int a, b, c;
};
struct Node s = {6, 6, 6}; //定義結構體變量
struct Node* p = &s; //定義指向s的結構體指針
printf("%d %d %d\n", p->a, p->b, p->c); //藉助指針訪問結構體數據
//Output:6 6 6
三 指針傳遞和引用傳遞
1, 指針傳遞
void swap(int* a, int* b)
{ //定義指針,在原地址操作
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int a = 1, b = 2;
swap(&a, &b); //將地址傳遞過去
printf("%d %d\n", a, b);
//Output: 2 1
}
2,引用傳遞
void swap(int& a, int& b)
{ //原變量的別名,同一內存單元(地址相同),僅僅是名稱不同
int temp = a;
a = b;
b = temp;
}
int main() {
int a = 1, b = 2;
swap(a, b);
printf("%d %d\n", a, b);
//Output: 2 1
}
三 指針函數和函數指針
1, 指針函數:返回值爲指針類型,其他和普通函數一樣
int* swap(int* a, int* b)
{
int temp = *a;
*a = *b;
*b = temp;
return a;
}
int main() {
int a = 1, b = 2;
int* p = swap(&a, &b);
printf("%d %d %d\n", a, b, *p);
//Output: 2 1 2
}
2, 函數指針:函數也有自己的地址,其爲指向函數的指針
int add(int x, int y)
{
return x + y;
}
int (*f) (int,int); //聲明函數指針
int main()
{
f = &add; //f函數指針,指向add函數
printf("%d\n", (*f)(1, 2));
return 0;
}
**未完待續。。。 **
例題 1:
編寫一函數len,求一個字符串的長度,注意該長度不計空格。要求用字符指針實現。在主函數中輸入字符串,調用該len函數後輸出其長度。
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
int len(char *sp)
{
int ans = 0;
while(*sp != NULL)
{ //判斷所指區域是否合法
if(*sp != ' ') ans++;
sp++;
}
return ans;
}
int main()
{
char s[105];
gets(s);
printf("%d\n", len(s));
return 0;
}
例題 2:
求n個整數中的最大的兩個元素。
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
void LargestTow(int a[], int n, int *pfirst, int *psecond)
{
for(int i = 2; i < n; ++i)
{
if(a[i] > *psecond)
{ //正常過程求解
if(a[i] > *pfirst)
{
*psecond = *pfirst;
*pfirst = a[i];
}
else
{
*psecond = a[i];
}
}
}
}
int a[1010];
int main()
{
int n;
scanf("%d", &n);
for(int i = 0; i < n; ++i)
scanf("%d", &a[i]);
int *p1, *p2; //要給出指針所指向的對象,否則會報錯
if(a[0] > a[1]) p1 = &(a[0]), p2 = &(a[1]);
else p1 = &(a[1]), p2 = &(a[0]);
LargestTow(a, n, p1, p2);
printf("%d %d\n", *p1, *p2);
return 0;
}
例題 3:
將輸入的四個整數按由大到小的順序輸出。
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
void psort(int* pa, int* pb, int* pc, int* pd)
{
int *p[4] = {pa, pb, pc, pd};//指針數組
for(int i = 0; i < 4; ++i)
for(int j = 0; j < 3; ++j)
if(*(p[j]) < *(p[j + 1]))
swap(*(p[j]), *(p[j + 1]));
}
int main()
{
int a, b, c, d;
scanf("%d %d %d %d", &a, &b, &c, &d);
psort(&a, &b, &c, &d); //c用指針,c++可用引用
printf("%d %d %d %d\n", a, b, c, d);
return 0;
}