C/C++学习之指针

C/C++学习之指针


什么是指针

指针:一个变量的地址称为该变量的指针。
指针变量:用来存放一个变量的地址的变量称为指针变量。但常把指针变量简称为指针。

指针的用法

//指针p被初始化,&为取址符,表明p的初值为n的地址&n。
int n;
int *p = &n;
//指针q被赋值,q的初值为&n,则*q等于n;符号*为指针运算符。
int *q;
q = &n;

&和*的关系

若p = &a,则 &p = p;&p = p;
可见&和*在一起,抵消彼此作用。

指针引用时需要注意点

  • 指针变量是用来存放地址的,不要给指针变量赋常量
//错误写法: 
int *p;
p = 1000;
  • 指针变量没有指向确定的地址前,不要对他所指向的对象赋值
// 错误写法:
int *p, a = 5; 
*p = 5;
//纠正: 表明p指向的变量b=5
int *p, b; 
p = &b; 
*p = 5;

指针变量作为函数参数

在C语言中,当指针变量作为函数参数,其作用是将一个变量地址传送到另一个函数。
此时形参从实参获得了变量的地址,也就是说实参和形参指向同一个变量,当形参指向的变量发生变化时,实参指向的变量也随之变化。

#include <stdio.h>
void swap(int *p1, int *p2)
{
    int p = *p1;
    *p1 = *p2;
    *p2 = p;
}
int main()
{
    int a = 3, b = 4;
    int * ptr1, ptr2;
    ptr1 = &a; 
    ptr2 = &b;
    swap(ptr1, ptr2);
    printf("%d, %d\n", a, b);   
    return 0;
}
/***输出***
4,3
*********/

但如果上面的例子改变的不是指针形参指向的变量的值,而是改变了指针形参的值,则效果是不一样的。

//例如将上面的swap函数换成如下:则输出a和b的值不变
void swap(int *p1, int *p2)
{
    int *p = p1;
    p1 = p2;
    p2 = p;
}
/***输出***
3,4
*********/

指向函数的指针

函数作为一段程序,在内存中也要占据一片存储区域,它有一个起始地址,即函数的入口地址,这个地址称为函数的指针。可以定义一个指针变量指向函数,然后通过指针调用函数。
一般形式如下:

类型名(*指针变量名)();
例如:
int(*p)()

C语言规定函数名就是函数的入口地址。所以当指向函数的指针变量等于一个函数名时,表示该指针变量指向函数。此时可以通过指向函数的指针调用该函数。
形式为如下:

(*指针变量名)(实参表)

指向函数的指针变量主要有两个用途:

  • 调用函数
  • 将函数作为参数在函数间传递
//例如:求两个数中较大的数
#include <stdio.h>
int max(int x, int y)
{
    int z = (x>y)?x:y;
    return z;
}
int main()
{
    int a = 1;
    int b = 2;
    int c;
    int(*p)(int, int);
    p = max;
    c = (*p)(a,b);    //调用max函数
    printf("%d, %d, max is %d\n", a, b, c);
}
/****输出****
1,2,max is 2
***********/

返回值为指针的函数

返回值为指针的函数形式:

类型名 *函数名 (参数表)

//返回值为整型指针的函数
int *max(int *x, int *y)
{
    int *q;
    q = (*x > *y) ? x : y;
    return q;
}

指针与数组

  • 指向数组元素的指针变量
//下面两句等价;并且有p+i和a[i]都表示a[i]的地址;
//*(p+i)和*(a+i)表示p+i和a+i所指向的数组元素a[i]的值
//由此可见,引用一个数组元素有两种方法:下标发:a[i]和指针法:*(a+i)
int a[5], *p;
int *p = a;
int *p = &a[0]
  • 数组和指针不等价

    考虑如下两个声明:

int a[3];
int *b;

声明一个数组时,编译器将根据声明所指定的元素数量为数组保留内存空间,然后在创建数组名,它的值是一个常量,指向这段空间的起始地址。
声明一个指针变量时,编译器只为指针本身保留内存空间,指针变量并未被初始化为任何现有的内存空间。
因此,上述声明后,表达式*a合法,而表达式*b确实非法的。*b将访问内存中某个不确定的位置,或者导致程序终止。
另一方面,表达式b++可以通过编译,但a++却不行,因为a的值是一个常量。而指向数组元素的指针可以自增和自减,方便了数组元素的操纵。

  • 指针和多维数组

在了解指正和多维数组的关系前,首先了解多维数组的特性:
(1)C语言把二维数组看做是一维数组的集合,即二维数组是一个元素为一维数组的一维数组;
(2)不带任何下标的二维数组名表示二维数组的起始地址,进行加法操作时则表示作为其他元素的一个一维数组(即二维数组的一行)的起始地址;
(3)只带一维下标的二维数组名表示作为其元素的一个一位数组(即二维数组的一行)的起始地址,对其进行加法操作时表示该一维数组(即二维数组的一行)的一个元素地址。
例如:

int a[2][3], (*p)[3], *q;
p = a;     
q = a[0]; 

此时,p+1等同于a+1,指向包含3个元素的一维数组a[1],所以(p+1)等于一维数组名a[1],(P+1)+1等于a[1]+1,所以((p+1)+1)=a[1][1];
q、a[0]、&a[0][0]相同,P+1等于a[0]+1,都指向a[0][1],即*(p+1)=a[0][1];

指针与字符串

字符串以数组形式存储,故字符串的本质是一维数组,指针和数组的原则适用于指针和字符串。

char *str = "hello";    //(1),合法

char *str; 
str = "hello"   //(2)与(1)等价,合法

char *str="hello";  
*str = "china"  //(3)不合法

一个字符指针变量只能指向一个字符数据,不能同时指向多个字符数据,更不能把字符串全部放在指针变量中,故表达式(3)不合法。

指针数组

C语言规定如果一个数组的元素都是指针类型,则称之为指针数组。

指针数组定义的形式为:
类型名 *数组名[常量表达式]

//表示指针数组a中每个元素都是指向int型变量的指针变量。
int * a[5];

指向指针的指针

一般形式:
类型名: **指针变量名

int **p, *a, b;
a = &b;
p = &a; 
/***则有***
p = &&b; 
*p = a; 
**p = b;
******/

指向结构变量的指针变量

一般形式:
struct 结构体名 *p

对结构体变量的成员的引用:

  • 结构体变量名.成员
  • (*结构体变量名).成员
  • 指针变量->成员名

猜你喜欢

转载自blog.csdn.net/walkerkalr/article/details/81148752