一 概念
前言:指针变量就是变量,指针就是地址。
首先考虑四个问题:指针变量的类型,指针所指向的类型,指针的值或是指针所指的地址,指针本身所占据的内存区。
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;
}