黑马程序员——指针学习小结

本文详细介绍了C语言中的指针,包括基本概念、指针的定义、赋值和引用,以及指针在函数参数、数组、字符串和函数指针中的应用。通过实例展示了如何使用指针交换变量值、遍历数组、复制字符串和实现多返回值。还探讨了二维数组指针、动态内存分配和指针在函数返回值中的角色,强调了正确使用指针的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

———-android培训、Java培训、iOS培训,期待与您交流———-

基本概念

一、名词:

指针:变量的地址。
指针变量:存放变量地址的变量。

二、定义、赋值和引用

  • 定义: 数据类型 *变量名;
    例:int *p;
  • 赋值:指针变量的值必须是地址。指针变量只能指向同类型的变量。例:
  • int a = 1;int *p = &a;
    int a = 1;int *p;p = &a;
  • 引用
    引用一个已经定义的指针变量有两种类型:

    1. 直接引用指针变量名。

      int a = 1; int *p = &a;
      printf("%p",p);//打印a的地址
    2. 在指针变量名前加”*”,引用指针变量所指向的值。

      int a = 1; int *p = &a;
      printf("%d",*p);//打印a的值

在引用指针变量时,指针变量名前的星号的作用是取指针所指的地址的值。显然在运用指针时”*”有两个作用:(1)定义指针变量时作为标识符号,声明这是一个指针变量。(2)引用指针变量时作为间接访问运算符,取指针所指向的对象的内容。

基本的指针使用

指针变量作为函数参数(实现多返回值)

先来看下面这个例子,通过使用指针实现使用函数交换两个变量的值。

#include<stdio.h>
void swap(int *pointer1,int *pointer2){
    int temp = *pointer1;
    *pointer1 = *pointer2;
    *pointer2 = temp;
}

int main(){
    int a = 1,b = 2;    
    int *p1 = &a,*p2 = &b;
    swap(p1,p2);
}

说明:在swap函数中,传入的是两个指针变量,进行交换的是两个指针变量所指向的变量的值,因此当函数结束,内存释放后,*p1和*p2的值已经改变。

这是指针的一大优点,可以通过子函数影响主函数中的变量,可以实现函数多返回值。

****错误用法****
将swap函数写成如下形式:

void swap(int *pointer1,int *pointer2){
    int *temp; 
    *temp = *pointer1;
    *pointer1 = *pointer2;
    *pointer2 = temp;

这种写法的错误在于,定义了指针变量temp,但并没有为其赋值,所以他指向的是一个未知的地址的值。下一语句向*temp赋值可能会导致系统错误,因此这种做法是错误的。

数组与指针

一、数组元素的指针

  • 定义、赋值和引用
int a[3];
int *p = &a[0];//指针变量p指向数组元素a[0]
int *p1 = a;//指针变量p1指向数组a的首地址
/*数组的首地址和数组第0个元素的地址相同*/
*p = 1;//对p所指向的变量(即a[0])赋值
/*可以通过指针对数组元素赋值*/
*(p+1) = 2;//对p所指向的下一个变量(即a[1])赋值
/*可以通过对指针变量p加或减移动指针,p+1指向同一数组的下一元素*/

由于a代表数组的首地址,因此*a=a[0], *(a+i)=a[i]。(a+i所代表的地址实际是p+i*d,d是一个数组元素所占的字节数)若int *p = a;则p+i=a+i, *(a+i)=*(p+i)=a[i]=p[i]。注意,p[i]与a[i]等价。

应用举例,使用指针输出数组的元素:

void main(){
    int a[10];
    int *p,i;
    for(i=0;i<10;i++){
        scanf("%d",&a[i]);
    }
    printf("\n");
    for(p=a;p<(a+10);p++{
        printf("%d ",*p);
    }
}
//由于不用在每一次输出时都计算a[i]的地址,
//因此使用指针比传统方法拥有更高的运行效率
  • 关于指针变量的自增自减
    指针变量自增自减可以实现在数组中相邻元素之间移动,但是当与*结合时要注意运算顺序。
int a[10];
int *p = a;
p++;//使p指向下一个元素,即a[1]
*p++;//等价于*(p++),作用是先得到p指向的变量的值,然后使p指向下一个变量
*++p;//等价于*(++p),作用是先使p指向下一个变量,然后取*p
++*p;//等价于++(*p),作用是使*p1

如果指针变量p当前指向数组a的第i个元素,则
(1)*(p++)相当于a[i++],即先曲a[i]的值再使i+1;
(2)*(++p)相当于a[++i],即先使i+1,再取a[i+1]的值;
(3)++(*p)相当于a[i]+1,即取a[i]的值然后加1。

应用举例,倒序数组元素:

#include <stdio.h>

void inv(int *x,int n){
    int i,j;
    i = 0;j = n-1;
    while(i<j) {
        int temp;
        temp = *(x+i);
        *(x+i) = *(x+j);
        *(x+j) = temp;
        i++,j--;
    }
}

int main(int argc, const char * argv[]) {
    int a[10]={3,6,11,45,2,77,33,16,83,8};
    int n = sizeof(a)/sizeof(int);//求数组的长度
    inv(a,n);
    for (int i =0; i<n; i++) {
        printf("%d ",a[i]);
    }
    return 0;
}
  • 两个指针变量可以相减
    如果两个指针变量指向同一个数组中的元素,那么两个指针之差是两个元素之间的元素个数
  • 两个指针变量可以比较
    如果两个指针变量指向同一个数组中的元素,那么指向前面的指针变量小于指向后面的指针变量。即序号小的元素指针小于序号大的元素的指针。

二、二维数组的指针

对于一个二维数组:
int a[3][4]={{1,3,5,7},{9,11,13,15},{17,19,21,23}};
相当于是三个一维数组a[0],a[1],a[2]连续存储在内存中。在一维数组中,数组名存储的是首元素的地址,而在二维数组中,数组名存储的则是首个一维子数组的地址,对于本例来说数组名a存储的是a[0]的首地址,而a+1则存储的是a[1]的首地址。需要注意的是,a+1并不是a[0][1]的地址。可以认为系统将二维数组看作是一维数组,而把三个子数组看作是一维数组的三个元素。虽然a和a[0]的地址一样,但是对他们进行+1操作时产生的结果却不一样。
二维数组指针的存储

  • 关于二维数组取值的性质
表示形式含义地址
a二维数组名,指向一维数组a[0],即0行首地址2000
a[0],*(a+0),*a0行0列元素的地址2000
a+1,&a[1]1行首地址2008
a[1],*(a+1)1行0列元素a[1][0]的地址2008
a[1]+2,*(a+1)+2,&a[1][2]1行2列元素a[1][2]的地址2012
*(a[1]+2),*(*(a+1)+2),a[1][2]1行2列元素a[1][2]的值值为1

* 二维数组的指针变量
顺序输出二维数组的元素可以通过简单的for循环实现,代码如下:

//假设定义了一个二维数组a[3][4],指针变量p指向这个数组
for(p=a[0];p<a[0]+12;p++){
    printf("%d ",*p);
}

但是如果要迅速定位二维数组的某个元素,除了计算该元素在数组中的绝对位置(例如上例中a[1][2]的绝对位置就是p+5,取值可以直接用*(p+5)),更快捷的方法是使用如下的指针:
int (*p)[4];
该指针变量指向包含4个整型元素的一维数组。如果该指针变量指向上例中的二维数组,那么对p+1则相当于a+1。此时取a[1][2]的值就可以通过*(*(p+1)+2)直观的实现。

字符串指针

一、存储字符串的两种方法

使用数组存放字符串
char string[] = "hello";
使用字符指针指向字符串
char *str = "hello";

二、通过键盘输入给字符串赋值

  1. 使用字符串数组
    char str[10];scanf("%s",str);
  2. 使用字符指针
    char *str=malloc(10);scanf("%s",str);
    注意:使用字符指针时不能像使用字符数组一样直接定义时候就使用scanf函数,必须先通过malloc函数为指针分配一块内存,然后通过scanf函数赋值。使用malloc函数应当先引入

三、应用举例,字符串复制

#include <stdio.h>
#include <stdlib.h>
void copyStr(char *from,char *to){
    while (*from!= '\0') {
        *to = *from;
        from++,to++;
    }
    *to = '\0';
}

int main(int argc, const char * argv[]) {
    char *str= malloc(4);
    scanf("%s",str);
    char *str2 = malloc(10);
    copyStr(str, str2);
    printf("STR2 = %s",str2);
    return 0;
}

关于copyStr函数中的while循环,还可以进行简化,在循环条件判断时完成复制,代码如下:

while ((*to = *from)!= '\0') {//在while循环判断的时候完成调换
        from++;
        to++;
    }

进一步,可以将指针的移动也整合到条件判断语句中,代码如下:

while ((*to++ = *from++)!= '\0');

由于’\0’的ASCII码是0,所以判断语句实际上就是在判断真假,因此最终可以简化如下

while (*to++ = *from++);

以上代码充分的体现出了指针和算法的强大。

四、应用举例2,格式化输出函数

可以用指针变量指向一个格式字符串,用它代替printf函数中的格式字符串,例如:

char *format;
format = "a = %d,b = %f\n";
printf(format,a,b);//相当于printf("a = %d,b = %f\n",a,b)

因此,只要改变指针变量format的字符串,就可以改变输入输出的格式。

指向函数的指针

可以用一个指针变量指向函数,然后用该指针变量调用函数。

一、定义方式

  • 声明
    数据类型 (*指针变量名)(函数参数列表);
    例如:int (*p)(int,int);
  • 赋值
    如果有一函数int test(int a,int b);p = test;使指针变量p指向该函数。
  • 调用
    如果有实参a,b,则p(a,b);就实现了通过指针调用函数。

二、指向函数的指针做函数参数

函数不能作为函数的参数,但是通过传递函数的指针,可以在一个函数中直接调用其他函数。例如:

void test(int (*p)(int),float (*q)(float)){
        int a;
        float b;
        p(a);q(b);
    } 

相比于直接在函数中将要调用的函数写死,这种通过传递函数指针实现的函数调用更为灵活,当需要改变调用的函数时,只需要改变变参数即可,不需要修改代码。

返回值是指针的函数

一、定义

类型名 *函数名(参数列表)
例如:
int *search(int (\*p)[4]);//定义一个返回整型指针的函数,参数是一个指向有四个元素的一维变量的指针。

二、应用举例

有三个学生,每个学生四门课,输出有课程不及格的学生多所有成绩。

#include <stdio.h>

int *search(int (*p)[4]){
    int *pt;
    pt = *(p + 1);
    for (int i=0; i<4; i++) {
        if (*(*p+i)<60) {
            pt = *p;
        }
    }
    return pt;
}

int main(int argc, const char * argv[]) {
    int scores[][4]={{33,58,95,77},{38,90,58,41},{86,65,88,96}};
    int (*p)[4] = scores;
    int *q;
    for (int i=0; i<3; i++) {
        q = search(p+i);
        if (q == *(p+i)) {
            for (int j=0; j<4; j++) {
                printf("%d\t",*(q+j));
            }
            printf("\n");
        }
    }
    return 0;
}
附:各种指针的定义
定义含义
int *p;整形变量指针
int (*p)[4];指向包含4个元素的一维数组的指针
int *p[4];包含4个元素的指针数组
int (*p)(int,int);指向函数的指针,该函数拥有两个整型参数和一个整型返回值
int *p(int *a,int *b);返回值是指针的函数,该函数有两个形参
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值