赞
踩
首先要知道不管你的指针是什么类型,是几级指针,在同一个操作平台编译环境中,所占的内存空间都是一致的。如pc使用的是32位的,那就是 32/8=4,那就是4个字节内存空间。
认真点讲:在C语言中,char,int,long,double这些基本数据类型的长度是由编译器本身决定的。而char*,int*,long*,double*这些都是指针,回想一下,指针就是地址呀,所以里面放的都是地址,而地址的长度当前是由地址总线的位数决定的,现在的计算机一般都是32位的地址总线,也就占4个字节。
#include <stdio.h> #include <stdlib.h> int main() { int i = 1; int *p = &i;//分开写是 int *p;p=&i; printf("i = %d\n",i);//简单取值 printf("&i = %p\n",&i);//取出 i对应的地址 printf("p = %p\n",p); //p存储的是一个地址,这个地址是&i。 printf("&p = %p\n",&p);//p自己也有一个地址 printf("*p = %d\n",*p);//相当于在p的存储的地址中取值,而p的存储的地址是&i对应的地 //址,在这个地址里取值,就是i的值。 return 0; }
解释:通俗点说,i变量是在内存有地址的,这个地址比如说0x2000,实际上对应我的电脑是0x7fff1035aedc,在图上可以看见;而这个i的变量对应的值是1。而指针p是存储i这个变量对应的地址,因为指针是负责存地址的,由上式 int *p = &i可知道,但是p这个指针自己也在内存也存有一块地址,比如说是0x3000,那么这个是指针自身的地址,&p=0x3000,*p = *(&i) = i。上述是一级指针。二级指针继续往下看,
#include <stdio.h> #include <stdlib.h> int main() { int i = 1; int *p = &i;//分开写是 int *p;p=&i; int **q =&p; printf("i = %d\n",i);//简单取值 printf("&i = %p\n",&i);//取出 i对应的地址 printf("p = %p\n",p); //p存储的是一个地址,这个地址是&i。 printf("&p = %p\n",&p);//p自己也有一个地址 printf("*p = %d\n",*p);//相当于在p的存储的地址中取值,而p的存储的地址是&i对应的地 //址,在这个地址里取值,就是i的值。 printf("q = %p\n",q); printf("&q = %p\n",&q); printf("*q = %p\n",*q); printf("**q = %d\n",**q); return 0; }
说到指针,我们也不能忘记了还有两个指针,一个是空指针,一个是野指针。
空指针:一开始不知道这个指针要具体存放啥时,就先将其设为空指针,常见为NULL。
野指针:当前这个指针所指向的空间是不确定的,但还需要使用。
#include "stdio.h"
#include "stdlib.h"
int main()
{
int *p = NULL;//空指针
int *q;//野指针
return 0;
}
#include <stdio.h> #include <stdlib.h> int main() { int a[3] = {1,2,3}; int i; int *p = a; for(i = 0;i < sizeof(a)/sizeof(a[0]);i++)//sizeof a 表示是整个数组占据的大小,sizeof a0 表示是第一占据大小 相除可以得到具体多少块 { printf("%p-->%d\n",&a[i],a[i]); printf("%p-->%d\n",a+i,p[i]); printf("%p-->%d\n",p+i,*(a+i)); printf("%p-->%d\n",&p[i],*(p+i)); } return 0; }
潇洒的结论:
a[i]可表示 a[i] = *(a+i) = *(p+i) = p[i]
&a[i]可表示 &a[i] = a+i = p+i = &p[i]
#include <stdio.h> #include <stdlib.h> int main() { int a[3]; int i; int *p = a; for(i = 0;i < sizeof(a)/sizeof(*a);i++) printf("%p-->%d\n",&a[i],a[i]); for(i = 0;i < sizeof(a)/sizeof(*a);i++) scanf("%d",p++); //scanf("%d",&a[i]); //scanf("%d",&p[i]); p = a;//将自增完的地址重新赋值 for(i = 0;i < sizeof(a)/sizeof(*a);i++,p++) printf("%p-->%d\n",p,*p); return 0; }
#include <stdio.h> #include <stdlib.h> int main() { int a[6] = {5,1,7,3,8,3}; int y; int *p = &a[1]; y = (*--p)++;//在p地址的基础上地址自减一个元素,而p指向是a[1]的数值,--的话就是a[0]对应的值,这是*--p的 //在执行完取值的操作后,进行++操作,取值完成之后的,是a[0]的值自增加1 printf("y = %d\n",y); printf("a[0] = %d\n",a[0]); return 0; }
结论一下:
如:total += *start; start++;
则可以写成一句:total += *start++;
解释:前者,start指向的是一个数组的首地址,第一步是把首元素取值start加上total的值得到一个数据赋值给total,然后start++表示自增加1,指向下一个数组的元素,start指向的是数组的类型指针,比如说int,那么start增加1时,他将增加一个int的大小。
后者,一元运算符※和++具有相同的优先级,但是在结合的时候是从右往左进行的。这就意味着++是应用于start,而不是应用于※start,也就是说指针自增加1,而不是说指针指向的数据增加1。后缀形式start++而不是++start 表示先把指针指向的数据加到total上,然后指针自增1。如果程序使用※++start,则顺序就变为指针先自增1,然后再使用其指向的值。然而如果使用(※start)++,那么会使用start所指向的数据,然后再使该数据自增1,而不是指针自增加1.这样指针指向的地址不变,但其中的元素却变成了一个新的数据。尽管※start++比较好用,但是为了清晰可见,应该使用※(start++)。
#include<stdio.h> int data[2] = { 100, 200 }; int moredata[2] = { 300, 400 }; int main(void) { int * p1, *p2, *p3; p1 = p2 = data; p3 = moredata; printf(" *p1 = %d, *p2 = %d, *p3 = %d\n",*p1, *p2, *p3); printf("*p1++ = %d, *++p2 = %d, (*p3)++ = %d\n",*p1++, *++p2, (*p3)++); printf(" *p1 = %d, *p = %d, *p3 = %d\n",*p1, *p2, *p3); return 0; }
结果:
#include <stdio.h> #include <stdlib.h> int main() { int a[2][3] = {1,2,3,4,5,6}; int i,j; int *p; p = &a[0][0]; //*(a+0),*a printf("a --> %p\n",a); printf("a+1 --> %p\n",a+1);//a+1:地址增加一个行元素 printf("p --> %p\n",p); printf("p+1 --> %p\n",p+1);//p+1:地址增加一个一个地址的元素,指针都是占据4个字节,下一个元素就是+4个字节. //就是说指针是在不能在列上面移动,不能在行上面移动。 printf("\n"); for(i = 0;i < 6;i++) printf("%d ",p[i]); printf("\n"); for(i = 0;i < 2;i++) { for(j = 0;j < 3;j++) { printf("%p --> %d\n",*(a+i)+j,*(*(a+i)+j)); //从起始位置a移动i行是a+i,加括号取*,降级变成列指针是 *(a+1),再加上j,相当于在列上移动,如果在括号取*就相当于取值 //printf("%p --> %d\n",&a[i][j],a[i][j]); } } return 0; }
#include <stdio.h>
#include <stdlib.h>
int main()
{
char str[] = "I love china!";
char *p = str+2; //*p指针指向字符串的首地址,+2表示向右移动来两位。
puts(str);
puts(p);
return 0;
}
#include <stdio.h> #include <stdlib.h> #include <string.h> //使用到strcpy man3 查看 int main() { char str1[] = "hello"; char *str2 = "hello"; printf("str1:%d %d\n",sizeof(str1),strlen(str1)); printf("str2:%d %d\n",sizeof(str2),strlen(str2)); strcpy(str1,"world"); //将后面的数据复制到指定的位置(前面) str2 = "world"; puts(str1); printf("\n"); puts(str2); printf("\n"); return 0; }
多说一句:sizeof与strlen是有着本质的区别,sizeof是求数据类型所占的空间大小,而strlen是求字符串的长度,字符串以/0结尾。 sizeof是一个C语言中的一个单目运算符,而strlen是一个函数,用来计算字符串的长度。sizeof求的是数据类型所占空间的大小,而strlen是求字符串的长度。
sizeof求的是类型空间大小,在前面说过,指针型所点的空间大小是8个字节,系统地址总线长度为64位时。
就是说一个指针指向数值,换句话来说指向数组的指针。
int (*p)[3]; --> int[3] *p;
之前学的是 int *p是说指针p指向一个int类型的指针,现在也是指针p指向一个int类型的数组。
1.本身就是一个指针,指针指向数组
2. int *p;这是整型指针。定义一个指针变量,目的是为了指向一个整型元素
#include <stdio.h> #include <stdlib.h> int main() { int a[2][3] = {1,2,3,4,5,6}; int i,j; int *p = *a; int (*q)[3] = a; //通常情况下,数组的大小,就是那个3,应该与二维数组的列数保持一致,这样方便移动不会报错 printf("%p %p\n",a,a+1); //a是一个常量 p则是一个变量 printf("%p %p\n",q,q+1); //和a一样对待 for(i = 0;i < 2;i++) { for(j = 0;j < 3;j++) { //printf("%p --> %d\n",*(a+i)+j,*(*(a+i)+j)); printf("%p --> %d\n",*(q+i)+j,*(*(q+i)+j)); //printf("%p --> %d\n",&a[i][j],a[i][j]); } printf("\n"); } return 0; }
简单的说就是存放指针的数组
如:int *arr[3]; --> int *[3] arr;
[存储类型] 数据类型 * 数组名 [长度]
1.首先这是一个数组 数组就要有数组名 那么定义一个 arr[3]; 数组名为arr内部有3个成员
2.其次这数组里面每一个元素都是一个指针 因此是 int *arr[3];
例:
#include <stdio.h> #include <stdlib.h> #include <string.h> int main() { int i,j,k; char *tmp; char *name[5] = {"Fllow me","Basic","Great","Fortran","Computer"}; for(i = 0;i < 4;i++) { k = i; for(j = i+1;j < 5;j++) { if(strcmp(name[k],name[j]) > 0) k = j; } if(k != i) { tmp = name[i]; name[i] = name[k]; name[k] = tmp; } } for(i = 0;i < 5;i++) puts(name[i]); return 0; }
结果:
const作用:把某些内容常量化,约束某些内容不能变化,优点就是检查语法 。
#define PI 3.14
而宏定义是不进行编译检查的,在编译中只是简单替换,不检查语法。
#include <stdio.h>
#include <stdlib.h>
int main()
{
//float pi = 3.14; //用于一个变量pi来保存3.14这个常量值,而变量实在程序运行中时刻有可能改变的值,
const float pi = 3.14;// 这是定义。而当去前的变量的pi,const把一个变量常量化,通常用于希望保存一个不需要改变的量。
//pi = 3.14159; //这样的话会报错,不能向只读的变量赋值
float *p = π //间接去改变常量的数值,而此时定义的初始化丢弃了指针目标类型的限定,说直接点就是可以改变了。
*p = 3.14159;
printf("%f",pi);
return 0;
}
const int *p; int const *p ;这两个都是常量指针
int *const p;这个就属于指针常量
const int const p;这个既是常量指针又是指针常量
常量指针定义:const后加p(p地址存放的具体值),用来保护这个值不被改变
指针常量定义:*const后加p(p为存放值的地址),用来保护这个地址不被改变
说一个简单的区别记法:先看到哪个(const 和 ),哪个在前就按照那个读取,如果是const就是常量指针,如果是 就是指针常量。
#include <stdio.h> #include <stdlib.h> int main() { int i = 1; int j = 100; const int *p = &i; i = 10; //这样可以更改,因为定义的i没有定义const, // *p = 10; // *p 是一个常量指针,不能改对应的数值 p = &j; //这样是可以的,因为可以改变指向的地址,那这样的*p就是100. printf("%d\n",*p); return 0; }
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i = 1;
int j = 100;
int *const p = &i; //而此时*p的值就是1
*p = 10; // *p 是一个指针常量,这个是可以改变数值的,打印的就是10
p = &j; //这样是不可以的,不能改变的指向的地址,但是可以改变目的值
printf("%d\n",*p);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i = 1;
int j = 100;
const int *const p = &i; //而此时*p的值就是1
// *p = 10; // 不能修改数值
//p = &j; //不能修改 指向的地址
printf("%d\n",*p);
return 0;
}
如 man fopen/man 2 open 查看定义
int open (const char *pathmame,int flags);
这表示只能查看传输过来的文件,前面有const,而 *pathname是保护文件的内容,不会改变放心传参。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。