C03指针


一 、 指针是什么?
1.指针是C语言中非常重要的数据类型,如果你说C语言中除了指针,其他你都学得很好,那你干脆说没学过C语言。
2.指针和内存联系很紧密。
2.1.一个bit就是一个二进制位。一个字节=8bit
3.关于内存相关(baidu)
3.1.编译时分配内存 : 编译时是不分配内存的。
此时只是根据声明时的类型进行占位,到以后程序执行时分配内存才会正确。
所以声明是给编译器看的,聪明的编译器能根据声明帮你识别错误。
3.2.运行时分配内存 :这是对的,运行时程序是必须调到“内存”的。
因为CPU(其中有多个寄存器)只与内存打交道的。
程序在进入实际内存之前要首先分配物理内存。
3.3.编译过程: 只能简单说一下,因为如果要详细的话,就是一本书了《编译原理》。
编译器能够识别语法,数据类型等等。
然后逐行逐句检查编译成二进制数据的obj文件,然后再由链接程序将其链接成一个EXE文件。
此时的程序是以EXE文件的形式存放在磁盘上。
3.4.运行过程: 当执行这个EXE文件以后,此程序就被加载到内存中,成为进程。
此时一开始程序会初始化一些全局对象,然后找到入口函数(main()或者WinMain()),就开始按程序的执行语句开始执行。
此时需要的内存只能在程序的堆上进行动态增加/释放了。
4.通常的机器都有一系列连续编号或编制的存储单元,通过这些存储单元可以单个进行操纵,可以以连续成组的方式操纵。

不同类型所占用的存储空间如下图
这里写图片描述


二 、 指针有什么用?
指针是一种保存地址的变量,在C语言中,指针常常是表达某个计算的唯一途径,另外指针通常可以生成更高效、更紧凑的代码。

三 、 指针怎么用?
  1. 定义的格式
    • 类名标识符 *指针变量名;
    • int *p;//声明
  2. 先定义后赋值
    • 简单取值
      int a = 10;
      int *p;
      p = &a;
      printf(“%d”, *p);
    • 简单改值
      *p = 9;
  3. 定义的同时赋值
    int a = 10;
    int *p = &a;
  4. 清空指针
    • p = 0;
    • p = NULL;

四 、 使用指针要注意什么?
1.指针只能指向某种特定类型的数据,也就是说,每个指针都必须指向某种特定的数据类型 
2.地址运算符&只能应用于内存中的对象,即变量与数组元素,它不能作用于表达式、常量或register类的变量
3.一元运算符*是间接寻址或间接引用运算符。当它作用于指针时,将访问指针所指向的对象那

五 、 指针应用代码举例
  • 例1 指针声明与引用
    int x=1,y=2,z[10];
    int *ip;//ip是一个指向整型int的指针
    ip=&x;//ip指向x
    y=*ip;//y现在的值是1
    *ip=0;//x现在的值是0
    ip=&z[0];//ip现在指向z[0]

  • 例2 指针与函数参数:交换两个次序颠倒的主元素

*由于C语言是以传值的方式将参数值传递给被调用函数,因此,别调用函数不能直接修改主调函数中变最的值。
如:

    void swap(int x,int y)
    {
        int temp;
        tmep = x;
        x = y;
        y = temp;
    }

则下列语句无法达到目的。

     swap(a,b);

*这时,可以使主调程序将指向所要交换的变量的指针传递给被调用函数 即

     swap(&a,&b);

函数定义如下

void swap(int *px,int *py)
    {
        int temp;
        tmep = *px;
        *px = *py;
        *py = temp;
    }//可以达到目标

  • 例3 指针与数组
// 初始化数组
int numbers[5] = {1,2,3,4,5};

// 标准数组表示法
int *ptr1 = numbers;
int val1 = numbers[0];

// 数组表示法取地址
int *ptr2 = &numbers[0];
int val2 = *(&numbers[0]);

// 指针加偏移表示法
int *ptr3 = numbers + 0;
int val3 = *(numbers + 0);

// 输出指针中的地址
printf("*ptr1 = %p\n", (void *)ptr1); //结果:0x7fff6be1de60
printf("*ptr2 = %p\n", (void *)ptr2); //结果:0x7fff6be1de60
printf("*ptr3 = %p\n", (void *)ptr3); //结果:0x7fff6be1de60

// 输出地址指向的int值
printf("val1 = %d\n", val1); //结果:1
printf("val2 = %d\n", val1); //结果:1
printf("val3 = %d\n", val1);//结果:1
//所有值都是相同的

  • 例4 地址算术运算
// 初始化数组
intnumbers[5] = {1,2,3,4,5};
inti = 0;

// 用数组表示法输出元素
for(i = 0; i < 5; i++ ) {
  intvalue = numbers[i];
  printf("numbers[%d] = %d\n", i, value);
}

// 用指针加偏移输出元素
for(i = 0; i < 5; i++ ) {
  intvalue = *(numbers + i);
  printf("*(numbers + %d) = %d\n", i, value);
}

// 仅用一个指针输出元素
int*ptr = numbers;
for(i = 0; i < 5; i++ ) {
  intvalue = *ptr++;
  printf("%d, *ptr++ = %d\n", i, value);
}
/*结果:
numbers[0] = 1
numbers[1] = 2
numbers[2] = 3
numbers[3] = 4
numbers[4] = 5
*(numbers + 0) = 1
*(numbers + 1) = 2
*(numbers + 2) = 3
*(numbers + 3) = 4
*(numbers + 4) = 5
0, *ptr++ = 1
1, *ptr++ = 2
2, *ptr++ = 3
3, *ptr++ = 4
4, *ptr++ = 5
//所有过程得到了相同的结果*/

  • 例5 字符指针与函数:复制字符串
//用数组实现
void strcpy(char *s, char *t)
{
    int i;
    i = 0;
    while ((s[i] = t[i]) != '\0')
    i++;
}
//用指针实现
void strcpy(char *s, char *t)
{
    int i;
    i = 0;
    while ((*s = *t) != '\0') {
    s++;
    t++;
    }
}

  • 例6 指针数组以及指向指针的指针
int main()
{
    int a[5]={1,3,5,7};
    int *n[4]={&a[0],&a[1],&a[2],&a[3]};//指针数组
    int **p,i;//**p为指向指针的指针
    p=n;
    for(i=0;i<4;i++)
      { 
        printf("%d\t",**p);p++; 
      }
    return 0;
}

结果:1 3 5 7


  • 例7 指向函数的指针:比较大小
#include <stdio.h>
#include <stdlib.h>

 int main()
{
    int max(int,int);
    int (*p)(int,int);//定义函数指针
    int a,b,c;
    p = max;//指向函数
    scanf("%d,%d",&a,&b);
    c = (*p)(a,b);//用指针调用函数
    printf("a=%d,b=%d,max=%d\n",a,b,c);
    return0;
}

int max(int x,int y)
{
    int z;
    if(x>y) 
        z = x;
    else 
        z = y;
    return(z);
}

六 、指针总结
- **主题 1:指针** 

1.将地址形象化地称为“指针”。意思是通过它能找到以它为地址的内存单元。
2.而地址指向内存单元
3.在程序中一般通过变量名来引用变量的值,因为通过变量名能找到相应存储单元的地址。
4.所有含有变量的语句,都是通过变量先找到其值,再去操作的。这种直接按变量名进行的访问,叫直接访问。
5.间接访问:将变量i的地址存放在另一个变量中,然后通过该变量来找到变量i的地址,从而访问i变量。
6.指向就是通过地址来体现的。
7.一个变量的地址就是叫做该变量的“指针”。
8.一个专门用来存放另一个变量的地址(即指针)则称它为指针变量。于是指针变量的值是地址。地址对应一个数,变量对应一个名。
9.指针变量,用来指向另一个对象(如变量,数组,函数等)。

- **主题 2:定义指针** 

1.定义指针变量:int * p;基类型 指针运算符 变量名
2.关于基类型
2.1.不同类型的数据在内存中所占的字节数和存放方式是不同的。就是说类型控制了数据在内存占的字节数
2.2.当取数据时,知道地址,然后还知道数据所占的字节数,才能准确把要的数据去出来。不然后有可能取多或取少。
2.3.类型和地址共同决定了数据位置信息。
2.4.于是指针移动一个位置,就是移动了其对应类型占用字节数,整型就是跨4个字节,字符就是跨1个字节,跳到了第二个变量的地址。
2.5.整型:4个字节 字符型:1个字节
2.6.一个变量的指针有两个方面:表示地址;指向类型 比如 int * p; p是一个指向整型数据的指针变量。

- **主题 3:引用指针**

1.引用指针变量
1.1.给指针赋值 p=&a;
1.2.引用地址
2.指针变量作为函数参数
2.1.作用是将一个变量的地址传送到另一个函数中
3.通过指针引用数组
4.数组的指针和数组元素的指针不同的
4.1.指针变量指向一个数组元素:int *p=&a[0];
5.现在引用数组元素:1)下标法2)指针法
6.使用指针法能使目标程序质量高(占内存少,运行速度快)。
7.在C语言,数组名代表数组中首元素的地址,所以数组名可以直接赋给指针变量。
8.在引用数组元素时指针的运算。
9.在引用数组元素时指针的运算。
9.1在指针指向数组元素时,可以对指针进行以下运算:1)加减一个整数2)自加自减3)同数组指针相减
10.通过指针引用数组元素
1)下标法2)指针法 *(a+i)
10.1)a[i]
10.2)通过数组名和元素序号计算数组元素地址,找出元素的值。 *(a+i)
10.3)用指针变量指向数组元素
for(p=a;p<(a+10);p++)
  printf("%d",*p);

11.注意
111.在使用指针变量指向数组元素时,应切实保证指向数组中有效的元素
11.2.指向数组的指针变量也可以带下标,但是必须弄清楚该指针变量的当前值是什么?
11.3.*p++:++和*同优先级 结合方向是自右向左。将先引用p的值,实现*p的运算,然后再使p自增1.
12.用数组名作函数参数
12.1.C语言调用函数时虚实结合的方法都是采用“值传递”方式,当用变量名作为函数参数时传递的是变量的值,
当用数组名作为函数参数时,由于数组名代表的是数组首元素地址,因此传递的值是地址,所以要求形参为指针变量。
12.2.在C语言中用下标法和指针法都可以访问一个数组,用下标法表示比较直观,便于理解。因此许多人愿意用数组名
作形参。
13.形参数组名实际上是一个指针变量,并不是真正地开辟一个数组空间。
14.如果有一个实参数组,想要在函数中改变此数组的元素的值,实参与形参的对应关系如下:实质是地址传递
14.1.形参和实参都用数组名
14.2.实参用数组名,形参用指针变量
14.3实参形参都用指针变量
14.4.实参是指针变量,形参是数组名

15.通过指针引用多维数组
15.1多维数组元素的地址
16.关于a[i]性质说明
16.1.从形式上看是a数组中序号为i的元素。
16.2.当a是一维数组名,则代表a数组序号为i的元素的存储单元,这时它是有物理地址的,是占存储单元的
16.3.当a是二维数组,则它是一维数组名,只是一个地址,并不代表某一元素的值(如同一维数组名只是一个指针常量一样)。

-**主题4:指向函数的 指针**

1.返回指针的函数
指针也是C语言中的一种数据类型,因此一个函数的返回值肯定可以是指针类型的
返回指针的函数的一般形式为:类型名 * 函数名(参数列表) 
2.指向函数的指针:  为什么指针可以指向一个函数?
2.1.函数作为一段程序,在内存中也要占据部分存储空间,它也有一个起始地址,即函数的入口地址。
函数有自己的地址,那就好办了,我们的指针变量就是用来存储地址的。因此,可以利用一个指针指向一个函数。
其中,函数名就代表着函数的地址。
2.2.指向函数的指针的定义:定义的一般形式:函数的返回值类型 (*指针变量名)(形参1, 形参2, ...);
3. 使用注意
3.1由于这类指针变量存储的是一个函数的入口地址,所以对它们作加减运算(比如p++)是无意义的
3.2指向函数的指针变量主要有两个用途:1)调用函数2)将函数作为参数在函数间传递 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值