20170214C语言提升08_指针_01变量及指针及数组

来源:互联网 发布:js表单验证表示时间 编辑:程序博客网 时间:2024/06/08 06:18

指针和变量的用法/区别:

1:变量:就是别名,用来访问存储空间
2:除了用变量名来访问存储空间,还可以使用指针来访问存储空间。
    注意:变量名访问会比指针更加的安全。指针是在变量名无法使用的场合才会用指针。
3:变量名无法使用的场合:
    1:局部变量进行参数传递的时候。
    2:动态分配内存的时候,局部变量无法实现。
4:指针也是一个变量,指针也有自己的存储空间,指针的变量名也是这块存储空间的别名,指针也会有指针(二级指针)。
5:指针的本质是 保存内存地址的变量。但凡是用到指针,就需要解指针,就是间接访问。
6:使用指针的效率会比使用变量低一些!
#include <stdio.h>int main(){int n = 10;//变量,直接访问int *pn = &n;//指针,间接访问n = 100;*pn = 1000;return 0;}//一下问对应的汇编代码。
对应的汇编代码为
int n = 10;//变量,直接访问009113D8  mov         dword ptr [n],0Ah  int *pn = &n;//指针,间接访问009113DF  lea         eax,[n]  009113E2  mov         dword ptr [pn],eax  n = 100;009113E5  mov         dword ptr [n],64h  *pn = 1000;009113EC  mov         eax,dword ptr [pn]  009113EF  mov         dword ptr [eax],3E8h  return 0;009113F5  xor         eax,eax 

    从汇编代码可以看出,间接访问是先将n的地址放到eax,然后将eax放到pn里面。赋值的时候,变量是一步到位,只用指针的话,回先将pn里面保存的地址取出来放到eax里面,然后才访问赋值。他有一个寻址的过程。可以看出使用变量的效率明显会被指针高一些。

    指针本身占用空间!

7:指针和const的结合:

const本身是左结合,左数右址不变!

#include <stdio.h>void foo(int *n){*n = 100;}int main(){int n = 100;//左数右址,const在*左边代表指针指向的数据为常量,const在*右边代表指针本身值不能改变。const int *p;//指针指向的值不可变int const *p1;//指针指向的数据不可变int* const p2;//指针内部保存的地址不可变const int * const p3;//指针自己的值和指向的值都不可更改const int const * const p4;//同上,但是没必要弄这么多constreturn 0;}


总结:const在*号左边代表里面的数据为常量,在*号右边代表指针本身为常量(不能再指向其他地址)。

数组和指针:

1:数组:相同变量类型的一个集合。
2:数组名:数组名和指针很像,使用的时候也有很多相似的地方。大部分地方我们何以将数组名认为是一个常量指针,以下两个场合不一样:
    1:sizeof()的时候:指针大小恒定为4,数组名则与数组大小相关。
    2:做取地址运算的时候:指针取地址得到的就是指针占用的地址,数组名有两个含义:1:数组的首元素地址,2:数组的地址。对数组名取地址得到的就是数组的地址,还是数组的首地址。所以对于 数组名和数组名取地址,两个得到的是一样的,但含义不一样。对两者进行+1,++等操作的时候,两者不一样,数组名++带有类型,数组名取地址之后的++加的大小为数组大小。
#include <stdio.h>int main(){int array[10] = { 0, 1, 2, 3, 4, 5 };int *parray = array;//数组的首地址int *paddarray = &array;//数组的地址//warning C4047: “初始化”:“int *”与“int (*)[10]”的间接级别不同printf("%p\t%p\t%p\t%p\n", parray, paddarray, parray + 1, paddarray + 1);//前两个相同,后两个都是+4printf("%p\t%p\t%p", array, array + 1, &array + 1);//前者+4,后者+40//array + 1 = array + sizeof(*array)//计算方式//&array + 1 = &array = sizeof(*&array)return 0;}

    对于二位数组也是一样的!上代码:

#include <stdio.h>int main(){char carray[100] = { 0 };//元素大小是1,数组大小是100;//首元素地址偏移的时候是+1byte,数组偏移的时候是+100byte。char ccarr[100][100] = { 0 };printf("%p\t%p\t%p\t%p\t%p\t%p\n", ccarr, ccarr + 1, ccarr[0][0] + 1, ccarr[0] + 1, &ccarr[0] + 1, &ccarr + 1);//  首地址,首地址+100,第一个值+1,    首地址+1,    首地址+100,   首地址+10000return 0;}


3:数组是直接访问,指针是间接访问。

//other.c里面的内容char *pstr = "I Love Mark";//main.c里面的内容#include <stdio.h>extern char pstr[];//欺骗编译器说是一个数组,实际为一个指针int main(){printf("%s\n", pstr);//打印出乱码,这里是直接把pstr按char*的方式访问。打印出的是字符串的地址(但是是按char*,所以是乱码)。printf("%s\n", (char*)(*(unsigned int*)pstr));//打印I Love Markreturn 0;}//后面的方法为强转为指针,解指针后按char*打印。


4:两个指针之间的运算:    指针-指针:计算出来为地址偏移量,结果可正可负,带类型。可以用循环对内存空间进行遍历。    指针+指针:出错!指针间不可相加。    指针=指针 指针!=指针:比较的是指针保存的地址。也是在连续空间才有意义。注意:指针运算一般为连续内存空间内的操作。如果任意不相干的两个指针来运算是没有意义的,可以通过编译并得出结果,但结果是未定义的。和对野指针操作差不多,无意义的。

5:使用指针来访问数组的效率要大于只用下标来访问:

一般为比较老的代码才有,现在的编译器优化很多,实际两者速度差不多(Debug下指针快,Release下一样)。

#include <stdio.h>int main(){int array[] = { 1, 2, 3, 4, 5 };int *parray = array;array[3] = 5;printf("%d", array[3]);*(parray + 3) = 5;printf("%d", *(parray + 3));return 0;}


Debug下的部分汇编代码为

array[3] = 5;00E03C51  mov         eax,4  00E03C56  imul        ecx,eax,3  00E03C59  mov         dword ptr array[ecx],5  printf("%d", array[3]);00E03C61  mov         eax,4  00E03C66  imul        ecx,eax,3  00E03C69  mov         esi,esp  00E03C6B  mov         edx,dword ptr array[ecx]  00E03C6F  push        edx  00E03C70  push        0E05868h  00E03C75  call        dword ptr ds:[0E09114h]  00E03C7B  add         esp,8  00E03C7E  cmp         esi,esp  00E03C80  call        __RTC_CheckEsp (0E01136h)  *(parray + 3) = 5;00E03C85  mov         eax,dword ptr [parray]  00E03C88  mov         dword ptr [eax+0Ch],5  printf("%d", *(parray + 3));00E03C8F  mov         esi,esp  00E03C91  mov         eax,dword ptr [parray]  00E03C94  mov         ecx,dword ptr [eax+0Ch]  00E03C97  push        ecx  00E03C98  push        0E05868h  00E03C9D  call        dword ptr ds:[0E09114h]  00E03CA3  add         esp,8  00E03CA6  cmp         esi,esp  00E03CA8  call        __RTC_CheckEsp (0E01136h)  


Release下的汇编代码为

array[3] = 5;printf("%d", array[3]);00C21000  push        5  00C21002  push        0C22100h  00C21007  call        dword ptr ds:[0C22090h]  *(parray + 3) = 5;printf("%d", *(parray + 3));00C2100D  push        5  00C2100F  push        0C22100h  00C21014  call        dword ptr ds:[0C22090h]  00C2101A  add         esp,10h  


6:数组名当作参数传递的时候,会降级为指针。相当于传递的指针,是做的copy,在子函数里面可以改变这个参数,对外面没有任何影响。

#include <stdio.h>int foo(int **array)//指针的指针{int n = 10;*array = &n;//修改了数组里面的值,一般不会这么写,会有警告。return n;}int main(){int array[] = { 1, 2, 3, 4, 5 };foo(array);printf("%p", array);return 0;}


1 0
原创粉丝点击