指针和变量的用法/区别:
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; //同上,但是没必要弄这么多const
return 0;
}
数组和指针:
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;
}