小学生都看得懂的C语言入门(5): 指针
现在已经学到C语言的后面了, 快学完咯....
(一)取地址运算
先来看一下sizeof 计算所占字节
#include<stdio.h> int main() { int a; a=6; printf("%d\n",sizeof(int));//4 printf("%d\n",sizeof(double)); //8 printf("%d\n",sizeof(a));//4 return 0; }
之前 ,我们看到scanf("%d", &x); 中& 表示什么意思?
& 是为了获取变量的地址, 它的操作对象必须是变量,
#include<stdio.h> int main() { int i=0; printf("%p\n",&i); // 打印地址 return 0; }
得到 000000000062FE4C
#include<stdio.h> int main() { int i=0; int j; printf("%p\n",&j); printf("%p\n",&i); return 0; }
得到
000000000062FE48
000000000062FE4C
C与8 在16进制下相差4,(c相当于12); 说明在内存中他们两个是紧挨着放的,
C语言中分配变量是从顶向下的, 先定义的变量i 的地址更高, 后定义的变量j 的地址更低.
#include<stdio.h> int main() { int a[10]; printf("%p\n",&a); printf("%p\n",a);// 直接拿a 作为地址 printf("%p\n",&a[0]); printf("%p\n",&a[1]); return 0; }
得到
000000000062FE20
000000000062FE20
000000000062FE20
000000000062FE24
那么 可见 & a= a, 表示a[0]的地址.
(二)拿什么东东来记录变量的地址??? ----指针
首先介绍下:
#include<stdio.h>
int i;
int *p=&i;// 一般用p表示指针(point), p获得i的地址,p指向i
int *p,q; // p q 都是指针
int* p,q; // 只有p是指针
//指针变量
//指针变量的值是内存的地址,普通变量的值是实际的值,
void f(int *p);// 作为参数的指针 int i=0;f(&i);// 进行调用.. 取得地址进行调用
#include<stdio.h> void f(int *p); int main() { int i=6; printf("&i=%p\n",&i); f(&i); return 0; } void f(int *p) { printf(" p=%p\n",p); }
得到
&i=000000000062FE4C
p=000000000062FE4C
对比下
#include<stdio.h> void f(int *p); void g(int k); int main() { int i=6; printf("&i=%p\n",&i); // &i=000000000062FE4C f(&i); // p=000000000062FE4C g(i);//6 return 0; } void f(int *p) { printf(" p=%p\n",p); } void g(int k) { printf("i=%d\n",k); }
// 访问那个地址上的变量 *
// * 是一个单目运算符,用来访问指针的值所表示的地址上的变量.
int k=*p;
*p=k+1;
#include<stdio.h> void f(int *p); void g(int k); int main() { int i=6; printf("&i=%p\n",&i); // &i=000000000062FE4C f(&i); // p=000000000062FE4C g(i);//26 , 在f中被更改!! return 0; } void f(int *p) { printf(" p=%p\n",p); printf("*p=%d\n",*p); // 在f中得到了地址, *p 可以看成是一个 int 得到*p=6; *p=26; // 能够改变i的值?? 可以!! } void g(int k) { printf("i=%d\n",k); }
&i=000000000062FE4C
p=000000000062FE4C
*p=6
i=26
(三) 数组作为函数参数机理
之前提到过, 数组作为函数参数后, 函数内不能用sizeof 了, 这是为啥??
#include<stdio.h> void minmax(int a[],int len,int *min,int *max); int main(void) { int a[]={1,2,3,4,5,6,7,8,10}; int min,max; printf("main 中 sizeof(a)=%lu\n",sizeof(a)); //36 printf("main 中a的地址 a=%p\n",a); // a=000000000062FE20 minmax(a,sizeof(a)/sizeof(a[0]),&min,&max); printf("a[0]=%d\n",a[0]);// 100 能够输出100!! printf("min=%d,max=%d\n",min,max); return 0; } void minmax(int a[],int len,int *min,int *max) { int i; printf("minmax中 sizeof(a)=%lu\n",sizeof(a));//8 printf("minmax 中a的地址 a=%p\n",a); // a=000000000062FE20, 与上述一样? // 这是为什么? 这里的a 就是指针啊!! a[0]=100; // 不妨更改a[0]看看能够传递到main中 *min=*max=a[0]; for(i=1;i<len;i++) { if(a[i]<*min){ *min=a[i]; } if(a[i]>*max){ *max=a[i]; } } }
上述也说明了数组 作为函数的参数实际上就是指针, 这就解释了为什么在 函数参数中, 用int a[] , 方括号中不写数字, 函数中没法用sizeof 得到正确的元素个数了. int a[] 其实就是指针, 虽然看着是数组, 若把它改为指针, 得到
#include<stdio.h> void minmax(int *a,int len,int *min,int *max); int main(void) { int a[]={1,2,3,4,5,6,7,8,10}; int min,max; printf("main 中 sizeof(a)=%lu\n",sizeof(a)); //36 printf("main 中a的地址 a=%p\n",a); // a=000000000062FE20 minmax(a,sizeof(a)/sizeof(a[0]),&min,&max); printf("a[0]=%d\n",a[0]);//100 printf("min=%d,max=%d\n",min,max); return 0; } void minmax(int *a,int len,int *min,int *max) { int i; printf("minmax中 sizeof(a)=%lu\n",sizeof(a));//36 printf("minmax 中a的地址 a=%p\n",a); // a=000000000062FE20, 与上述一样? // 这是为什么? 这里的a 就是指针啊!! a[0]=100; // 不妨更改a[0]看看能够传递到main中 *min=*max=a[0];// 指针形式, 下面做改变可以传到main中去 for(i=1;i<len;i++) { if(a[i]<*min){ *min=a[i]; } if(a[i]>*max){ *max=a[i]; } } }
上述编译没有问题, 现在*a 是指针, 可是a[0] ,a[i] 都是当做数组在用它,
// 数组与指针存在某种联系!!
以下几种函数原型(之前写函数声明的地方)是等价的:
int sum(int a,int n);
int sum( int* ,int);
int sum( int ar[],int n);
int sum(int[], int);
数组变量是特殊的指针, 之前对数组a取地址可以不加& !!
printf("%p\n",&a);
printf("%p\n",a);// 直接拿a 作为地址
printf("%p\n",&a[0]);
,这三个一样的结果!!
(1) 但是对单个元素需要加&, 例如&a[1];
(2) [ ] 可以对数组做,也可以对指针做, p[0] 等价于 a[0]
(3) * 运算既可以对数组做, 也可以对指针做,
(4) 数组变量是 const 的指针, 不能被赋值
int a[]={1,2,3}; int b[];// int b[]=a;也是错误的!! b=a;
这样是错误的!!
下面两个是正确的:
int a[]={1,2,3}; int *q =a; //可以
int b[] ; // 相当于 int * const b; 是个常量指针