C语言之指针(二)

[TOC]文章目录

目录

前言

指针的运算

指针的其他运算形式

*p++

指针比较

指针的类型

小总结(指针的作用)

内存分配函数

malloc

内存释放函数

free()

常见问题


前言

本篇是有关C语言指针的知识点的部分总结。

指针的运算

#include<stdio.h>
int main()
{
    char ac[]={0,1,2,3,4,5,6,7,8,9,};
    cahr *p=ac;
    printf("p  =%p\n",p);
    printf("p+1=%p\n",p+1);
    printf("*p+1=%d\n",*(p+1));
    int ai[]={0,1,2,3,4,5,6,7,8,9,};
    int *q=ai;
    printf("q  =%p\n",q);
    printf("q+1=%p\n",q+1);
    printf("*q+1=%d\n",*(q+1));
    return 0;
}
输出:
p  =0xbffbad5a
p+1=0xbffbad5b
*(p+1)=1
q  =0xbffbad2c
q+1=0xbffbad30
*(q+1)=1

十六进制:0x2c=44,0x30=48          30-2c=4

sizeof(char)=1,sizeof(int)=4。所以当我们给一个指针去加1的时候,它不是在地址值上加一,而是在地址值上加一个sizeof。

给一个指针加1表示要让指针指向下一个变量

int a[10];

int *p=a;

*(p+n)<-->a[n]

如果指针不是指向一片连续分配的空间,如数组,则这种运算没有意义。

这些算术运算可以对指针做:给指针加、减一个整数(+、+=、-、-=)  递增递减(++/--)

                                               两个指针相减

#include<stdio.h>
int main(void)
{
    char ac[]={0,1,2,3,4,5,6,7,8,9,};
    cahr *p=ac;   //或写成*p=&ac[0]
    char *p1=&ac[5];
    printf("p1-p=%d\n",p1-p);
    int ai[]={0,1,2,3,4,5,6,7,8,9,};
    int *q=ai;
    int *q1=&ai[6];
    printf("q  =%p\n",q);
    printf("q1 =%p\n",q1);
    printf("*q1-q=%d\n",q1-q);
    return 0;
}
p1-p=5
q  =0xbff11d28
q1 =0xbff11d40
q1-q=6

十六进制:0x40-0x28=0x18  结果换算成十进制,为24

q1与q之间的地址直接相减的话为24,但运行结果为6。6=24/sizeof(int)

所以当两个指针相减时,编译器给的不是两个地址相减的差,给的是两个地址的差除以类型的sizeof,即两者之间能放几个这样类型的东西

指针的其他运算形式

*p++

我们常常在指针中看见 *p++,它指的是 取出p所指的那个数据来,完事之后顺便把p移到下一个位置去。

*的优先级虽然高,但是没有++高

作用:常用于数组类的连续空间操作;在某些CPU上,这可以直接被翻译成一条汇编指令

#include<stdio.h>
int main(void)
{
    char ac[]={0,1,2,3,4,5,6,7,8,9,-1}; 
    char *p=&ac[0]; 
    while(*p!=-1){                //-1不作为结果输出,它是一个结尾的标志
        printf("%d\n",*p++);
    }
    return 0;
}

指针比较

<,<=,==,>,>=,!=都可以对指针做。指针不能做乘除,可以做加减,可以做比较。

指针比较其实就是地址大小的比较。数组中的单元的地址肯定是线性递增的

0地址

任何程序中都有0地址,但是0地址通常是个不能随便碰的地址,所以指针不应该具有0值。因此可以用0地址来表示特殊的事情:

返回的指针是无效的;指针没有被真正初始化(先初始化为0)

NULL是一个预定定义的符号,表示0地址,有的编译器不愿意用0来表示0地址。

指针的类型

无论指向什么类型,所有的指针的大小都是一样的,因为都是地址。但是指向不同类型的指针是不能直接相互赋值的,这是为了避免用错指针。

指针的类型转换(初学者不建议使用)

void*表示不知道指向什么东西的指针,计算时与char*相同(但不想通)

指针也可以转换类型   int*p=&i;  void*q=(void*)p; //通过p去看i是个int,通过q去看i是个void

这并没有改变p所指的变量的类型,而是让后人用不同的眼光通过p看它所指的变量(不再当i是int,认为i是个void)

小总结(指针的作用)

  • 需要传入较大的数据时用指针作参数的类型,比如传数组
  • 传入数组后可以对数组做操作
  • 当函数返回不止一个结果时,可以用指针做参数让它带出结果
  • 当需要用函数修改不止一个变量的时候,比如swap,可以传指针进去让它帮助修改变量的值
  • 当需要动态申请内存的时候……

内存分配函数

如果输入数据时,先告诉个数,然后再输入要记录的每个数据,那么有C99的话,可以用变量做数组定义的大小。但是C99之前如何做呢?

那个时候就必须使用动态内存分配。就像这样写(用一个malloc函数):

int *a=(int*)malloc(n*sizeof(int));

malloc函数给它一个参数(说要多大的内存)。如果说要120个字节,n=30,30*sizeof(int)就是120个字节。malloc给一段空间,得到的是void*,还要把类型转换成int*。

#include<stdio.h>
#include<stdlib.h>

int main()
{
    int number;
    int* a;
    int i;
    printf("输入数量: ");
    scanf("%d",&number);
    //int a[number]  如果是C99的话,可以直接这样写
    a=(int*)malloc(number*sizeof(int));  /*malloc要的参数不是有多少个int,不是这个数 
                                           组有多少个单元,而是这个数组占据多少个空间。 
                                           所以malloc是以字节为单位的。*/
    for(i=0;i<number;i++){
       scanf("%d",&a[i]);
    }
    for(i=number-1;i>=0;i--){
        printf("%d ",a[i]);
    }  /*我们一旦用malloc得到了一块空间并给它交给了a,接下来我们所有对a的操作可以完全把a当 
       做数组来用*/
    free(a);  //我们用malloc在系统中要了一段空间,走之前要还回去
    return 0;
}

这就是过去用malloc做动态内存分配来实现数组的大小在运行的时候才确定。

malloc

需要加头文件:  #include<stdio.h>

原型:  void* malloc(size_t size);  //参数是size_t,返回的类型是void*

说明:向malloc申请的空间的大小是以字节为单位的,如果需要int,那么数量乘以sizeof(int),如果需要short,数量乘以sizeof(short)。因为在计算机中,内存就是一片连续的空间,是我们自己说的这个地方是int,那个地方是short,所以跟计算机要内存后,需要类型转换。

返回的结果是void*,需要类型转换为自己需要的类型。

(int*)malloc(n*sizeof(int))

malloc是跟系统要空间,空间总是有限的,如果申请失败则返回0,或者叫做NULL。

内存释放函数

free()

把申请得来的空间还给“系统”,申请过的空间,最终都是应该要还的,只能还申请来的空间的首地址。

常见问题

  • 忘了
  • 找不到合适的free的时机
  • free过了再free
  • 地址变过了,直接去free

申请了空间,但是没free,会导致长时间运行内存逐渐下降

解决方法:写了malloc就记住要去写free;需要对程序的架构有一些良好的设计,保证程序有恰当的时机去写free;需要多读代码,多写代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值