指针杂谈

指针杂谈

指针注意事项

  • 指针必须声明,并且初始化

  • 函数参数列表中的数组实际上是指针!!!所以一般需要传递数组长度,而不能使用sizeof(array) / sizeof(int)

  • *sizeof(array) == sizeof(int )

  • 但是可以使用数组的运算符[ ]来进行运算

  • 数组变量本身表达地址,所以

    •   int a[10];
        int *p = a;//无需使用&取地址
      
    • 但是数组的单元表达的是变量,需要用&取地址

    •   a == &a[0]
      
  • []运算符也可以对数组做,也可以对指针做:

    •   p[0] <==> a[0]
      
  • *运算符可以对指针做,也可以对数组做:

    •   *a = 25;
      
  • 数组变量是const的指针,所以不能被赋值

    •   int a[] <==> int * const a=...
      

指针与const(适用于C99)

指针本身可以是const,其指向的值也可以是const

指针是const

表示一旦得到了某个变量的地址,不能再指向其他变量

int *const q = &i;//q是const
*q = 26;//OK
q++; //ERROR

指针指向的值是const

表示不能通过这个指针去修改那个变量(并不能使那个变量成为const),p可以指向其他变量,i也可以重新赋值为其他。不变的是:不能通过*p去做赋值!!!

const int *p = &i;
*p = 26; //ERROR! (*p)是const
i = 26; //OK
p = &j;//OK

练习

int i;
const int* p1 = &i;	//是指不能通过p1去修改值---->通过指针不可修改
int const* p2 = &i;	//同上
int *const p3 = &i;	//p3不能再去指向其他变量---->指针不可修改

/*方法:判断哪个被const了的标志是const在*的前面还是后面?

const在前面,说明它所指向的东西不能被修改
const在后面,说明指针不能被修改

*/

技巧

保护数组值

因为把数组传入函数时传递的是地址,所以那个函数内部可以修改数组的值,为了保护数组内部不被函数破坏,可以设置为const

int sum(const a[], int length);

指针运算

指针相加

char a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
char *p  = a;
printf("p = %p
", p);
printf("p+1 = %p
", p+1);

int b[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int *q  = b;
printf("q = %p
", q);
printf("q+1 = %p
", q+1);

sgvOIK.png

指针+1的意思不是简单的地址值+1,而是指针指向下一个单元!!!

这也解释了为什么数组运算可以和指针一样,*p 就相当于a[0],*(p+1)就相当于a[1]

指针相减

指针相减计算结果不是他们之间的距离之差,而是他们地址之差/sizeof(类型)

特殊形式

*p++

  • 取出p所指的数据,然后将p指针移到下一单元去
  • *的优先级虽然高,但是没有++高
  • 常用于数组类的连续空间操作
  • 在某些CPU上,这可以直接被翻译为一条汇编指令

指针比较

  • < <= == >= > !=都可以对指针做
  • 比较它们在内存中的地址
  • 数组中的单元的地址肯定都是线性递增的

0地址

  • 内存中肯定存在0地址,但是通常0地址是一个不能随便碰的地址
  • 所以地址在实际中不应该具有0值
  • 因此可以使用0地址来表示特殊的事情:
    • 返回的指针是无效的
    • 指针没有被真正初始化(先初始化为0)
  • NULL是一个预定定义的符号,表示0地址
    • 有的编译器不愿意你用0来表示0地址

指针类型

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

指针的类型转换

  • void*表示不知道指向什么类型的指针

    • 计算的时候与char*相同(但不相通)
  • 指针也可以转换类型

    •   int *p = &i; 
        void *q = (void*)p;
      
    • 这转换并没有改变p所指的变量的类型,i仍然是整型,而是让人们用不同的眼光通过p看它所指向的变量(我不再认为你是int类型,而是void)

指针用处

  • 需要传入较大的数据时用作参数
  • 传入数组后对数组做操作
  • 函数返回不止一个结果
    • 需要用函数来修改不止一个变量
  • 动态内存的申请...

动态内存分配

在C99出来之后,可以使用变量来定义数组的大小,例如:

int num;
scanf("%d", &num);
int arr[num];

在C99之前,是需要动态申请内存的,例如:

int *a = (int*)malloc(n*sizeof(int));	//因为malloc返回的是void*,所以对于a来说还需要强转一下

...
free();

//动态申请之后,在程序结束时候,要free()一下,释放内存!

注意:

  • 需要导入头文件<stdlib.h>

  • 向malloc申请的空间的大小是以字节为单位的

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

  •   (int*)malloc(n*sizeof(int))
    
  • free()

    • 把申请得来的空间还给系统
    • 申请过的空间都需要还
    • 只能还申请来的空间的首地址,如果地址变过了,则会出错!

因为系统内存空间是有限的,如果系统在某个时间内存满了,此时malloc函数向系统申请内存空间,会怎么样呢?

  • 如果申请失败则返回0,或者NULL
  • 怎么知道系统能分配给你多大空间呢?
原文地址:https://www.cnblogs.com/Arong123/p/14320445.html