您的位置:首页 > 编程语言 > C语言/C++

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

2017-02-14 19:31 435 查看

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

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
,0Ah
int *pn = &n;	//指针,间接访问
009113DF  lea         eax,

009113E2  mov         dword ptr [pn],eax
n = 100;
009113E5  mov         dword ptr
,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;				//同上,但是没必要弄这么多const
return 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);//前两个相同,后两个都是+4
printf("%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,   首地址+10000
return 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 Mark
return 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c语言 编程 指针 存储