2017.12.02.C语言总结

指针变量

指针可以引出几个概念,指针变量,指针数组,数组指针。那么什么是指针呢,通过什么来进行指针的计算?
首先我们要知道有关指针的符号;
指针运算符
(1)取地址运算符&
取地址运算符&是单目运算符,其结合性为自右至左,其功能是取变量的地址。scanf函数及前面介绍指针变量赋值中,我们已经了解并使用了&运算符。
(2)取内容运算符*
   取内容运算符是单目运算符,其结合性为自右至左,用来表示指针变量所指的变量。在运算符之后跟的变量必须是指针变量。需要注意的是指针运算符和指针变量说明中的指针说明符 不是一回事。在指针变量说明中,’‘是类型说明符,表示其后的变量是指针类型。而表达式中出现的 ‘’ 则是一个运算符用以表示指针变量所指的变量。

下面我们定义一个指针变量:
int *p;//定义了一个int 型的指针,指针的名字叫p。
同样的,定义一个char *p;//和上面同样的理解。
类似的我们可以定义很多不同类型的指针变量。
但是我们需要知道的是,指针数组,数组指针。以及牵扯指针运算的数组问题,(感觉这是我们程序员关心的重点),但是往往在这方面,令人头痛的很。所以我们必须要很清楚的认识到自己在这方面的不足,然后才能不断地进步。
指针是一个变量,存放的是指针所声明类型的变量地址,申请指针就像是编译器向系统,申请了一个空间,但是不是存放的是变量,而是地址(就像是int a = 0存放的是一个int型的常量 0, 而指针会在程序员想用它的时候,指向一个相对应的类型的地址。)。
//int a = 0, *p = NULL;//同时定义一个指针和变量。
// p = &a ;//取a的地址,将其存放在p所占的空间里边。
之后就可以通过改变a所指向的地址里面的值来修改a的值。//实质上使用改变a的地址存放的值来改变变量的值。
//const int a = 1;//定义一个常量(我们知道的常量是不可变的,但是C语言是一个强类型的语言,程序员可以通过一系列的操作来达到自己的目的,但是在没有学习指针之前对于这个问题还是有些束手无力的,因为无法使用一般的方法来改变,例如:a = 2;编译器会认为这个不正确。所以很多人就是在指针这里懵的,我也是。)
我们可以定义一个指针,并将指针指向a,之后通过指针来指向。
// const int a =0;
// int *p = &a;
// *p = 1;
但是细心的我们发现在编译的时候,会有一个警告。忽略的话继续运行,会发现编译器抛出了段错误。说明普通的变量通过指针改变值得方法不可以使用。那么我们试一下另外一种方法。
定义一个指针,指针指向a的地址,但是a的地址被强制转换为一个int*指针类型。
所以指针指向指针可以运行,之后我们可以得到,a的值被改变。
//const int a = 0;
// int p = (int )(&a);
// *p = 1;
指针的威力从此可见,所以我们必须去谨慎的使用指针,因为指针会带来不可预见性的错误。而这仅仅是在指针操作单个元素的时候,通常面对我们的是很多的元素,来进行我们的操作。所以更需要来不断地进行一些操作。
而这就牵扯到了,数组指针,指针数组,的相关问题。所以我们进行一些操作的时候,我们就必须清楚的认识,来应对每一次的头脑风暴。

相似的也可以使用指针来指向对应数据类型的一维数组,使用方法和数组名相同。
我们可以拿一个程序举一个例子:

#include <stdio.h>
int main(void)
{
    int a[5] = {1,2,3,4,5};
    int i = 0;
    int * p = a;//数组名做右值可以当做地址。
    //数组名有一个很有意思的现象,就是相当于一词多义,可以做为数组名,也可以当做数组的首地址(数组在内存中是线性的,有一个首地址可以很快地找到),还可以当做数组的首元素。
    for(i=0; i<5; i++)
        printf("a[%d] = %d   ",i, a[i]);
    printf("\n");
    for(i=0; i<5; i++)
        printf("*(a+%d) = %d   ", i, *(a+i));// a+i 是指地址。
    printf("\n");
    for(i=0; i<5; i++)
        printf("p[%d] = %d   ", i, p[i]);
    printf("\n");
    for(i=0; i<5; i++)
        printf("*(p+%d) = %d   ", i , *(p+i));
    printf("\n");
    return 0;
}

我们从上面的关系可以看出,我们使用的四种方法都可以打印出a数组里面的元素。不同的两种打印方式(数组名和指向数组首地址的指针)相同。所以我们可以将数组名使用的时候,可以当做一个指针来操作,但是叫的时候还是叫一个一维数组的数组名。
之后的话,指针可以作为两个元素的交换的中介(使用交换函数的话)。

//交换两个数字的值。
#include <stdio.h>
void change(int *a, int *b)//如果传进来普通的变量,就是在普通变量的基础之上复制一份(多花了一份空间)来进行运算,指针的话,可以指向想要操作的数的地址,操作的是同一份数据元素。
{
    int c = 0;
    c = *a;
    *a = *b;//交换两个值地址上的值。
    *b = c;
}//不可返回函数里边新建的指针,因为,函数结束后,会释放这些指针。造成野指针 
int main(void)
{
    int a = 1, b = 2;
    change(&a,&b);//传的是地址。改变了实质
    printf("a = %d b = %d\n", a, b);
}//其他类型的元素基本相同。

指针数组,数组指针

这两个名字不同当然所代表的意思也就不同。我刚开始看到这就吓到了,主要是中文太博大精深了,整这样的简称太专业了,把人都绕晕了。从英文解释或中文全称看就比较容易理解。

指针数组:array of pointers,即用于存储指针的数组,也就是数组元素都是指针

数组指针:a pointer to an array,即指向数组的指针

还要注意的是他们用法的区别,下面举例说明。

int* a[4]     指针数组     

表示:数组a中的元素都为int型指针    

元素表示:*a[i]   *(a[i])是一样的,因为[]优先级高于*

int (*a)[4]   数组指针     

表示:指向数组a的指针

元素表示:(*a)[i]  
#include <stdio.h>
int main(void)
{
    int(* ptr_arr)[3];//定义一个指针数组。
    int arr[4][3];
    ptr_arr = arr;//指针数组指向arr数组
    int i = 0, j = 0, k = 0, l = 0;
    for(i=0; i<4; i++)
        for(j=0; j<3; j++)
            scanf("%d", &arr[i][j]);
    for(i=0; i<4; i++)
    {   
        for(j=0; j<3; j++)
        {   
            printf("%d ", ptr_arr[i][j]);//通过指针打印数组。
        }
        printf("\n");
    }
    return 0;
}
//或者
#include <stdio.h>
int main(void)
{
    int arr[6] = {1, 2, 3, 4, 5, 6};
    int *ptr_arr[6];
    int i = 0;
    for (i=0; i<6; i++)
    {
        ptr_arr[i] = arr+i;//将arr中的每个元素的地址赋给指针数组的每一个元素;
    }//arr + i表示在数组首地址的基础之上加上i个乘以int型字节的变量,就是具体的每个元素的地址。*(arr+i)表示取数组第几个元素。
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值