赞
踩
无关紧要的发现:读取过任意类型后,会留下一个缓冲区,在读取下一个字符前要么在 %c 前加上一个空格,要么提前用 getchar() 吃掉缓冲区
参考文章:链接: link
在C语⾔中创建变量其实就是向内存申请空间
上述的代码就是在(X86)也就是32位环境下创建了整型变量a,内存中申请4个字节,⽤于存放整数10,其中每个字节都有地址,上图中4个字节的地址分别是:
0x00CFFB34
0x00CFFB35
0x00CFFB36
0x00CFFB37
int a=12; int b; int *p; int **ptr;
p=&a; //&a 的结果是一个指针,类型是int*,指向的类型是
//int,指向的地址是a 的地址。
*p=24; //*p 的结果,在这里它的类型是int,它所占用的地址是
//p 所指向的地址,显然,*p 就是变量a。
ptr=&p; //&p 的结果是个指针,该指针的类型是p 的类型加个*,
//在这里是int **。该指针所指向的类型是p 的类型,这
//里是int*。该指针所指向的地址就是指针p 自己的地址。
*ptr=&b; //*ptr 是个指针,&b 的结果也是个指针,且这两个指针
//的类型和所指向的类型是一样的,所以用&b 来给*ptr 赋
//值就是毫无问题的了。
**ptr=34; //*ptr 的结果是ptr 所指向的东西,在这里是一个指针,
//对这个指针再做一次*运算,结果是一个int 类型的变量。
我们可以简单理解,32位机器( X86 )有32根地址总线,每根线只有两态,表⽰0,1【电脉冲有⽆】,那么⼀根线,就能表⽰2种含义,2根线就能表⽰4种含义,依次类推。32根地址线,就能表⽰2^32种含义,每⼀种含义都代表⼀个地址。
同理64位机器( X64 )
由此可得
#include <stdio.h>
//指针+- 整数
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int *p = &arr[0];
int i = 0;
int sz = sizeof(arr)/sizeof(arr[0]);
for(i=0; i<sz; i++)
{
printf("%d ", *(p+i));//p+i 这⾥就是指针+整数
}
return 0;
}
再比如指针ptr 的类型是int*,它指向的类型是int,它被初始化为指向整型变量a。接下来的第3句中,指针ptr被加了1,编译器是这样处理的:它把指针ptr 的值加上了sizeof(int),在32 位程序中,是被加上了4,因为在32 位程序中,int 占4 个字节。由于地址是用字节做单位的,故ptr 所指向的地址由原来的变量a 的地址向高地址方向增加了4 个字节。由于char 类型的长度是一个字节,所以,原来ptr 是指向数组a 的第0 号单元开始的四个字节,此时指向了数组a 中从第4 号单元开始的四个字节。
char a[20];
int *ptr=(int *)a; //强制类型转换并不会改变a 的类型
ptr++;
总的来说一个指针ptrold 加(减)一个整数n 后,结果是一个新的指针ptrnew,ptrnew 的类型和ptrold 的类型相同,ptrnew 所指向的类型和ptrold所指向的类型也相同。ptrnew 的值将比ptrold 的值增加(减少)了n 乘sizeof(ptrold 所指向的类型)个字节。就是说,ptrnew 所指向的内存区将比ptrold 所指向的内存区向高(低)地址方向移动了n 乘sizeof(ptrold 所指向的类型)个字节。
//指针-指针
#include <stdio.h>
int my_strlen(char *s)
{
char *p = s;
while(*p != '\0' )
p++;
return p-s;
}
int main()
{
printf("%d\n", my_strlen("abc"));
return 0;
}
指针的类型很多,是枚举不完的,于是我们只需要将几种重要的指针类型给琢磨清楚,别的就只需要稍加观察就能立即理解了。
要理解复杂类型其实很简单,一个类型里会出现很多运算符,他们也像普通的表达式一样,有优先级,其优先级和运算优先级一样。原则就是,从变量名处开始,根据富豪的优先级,既可以退出指针的类型。
int p;//最朴实无华的整型变量
int* p;//从p开始,与*结合,说明p是一个指针,再与int结合,说明指针所指向的元素是整形,所以p是一个返回整型类型的指针
int p[3];//从p开始,与[]结合,说明p是一个数组,再与int结合,说明数组里的元素是整形的,所以p是由整型类型组成的的数组
int* p[3];//从p开始,[]的优先级比*高,所以p先与[]结合,是一个数组,再与*结合,说明数组里的元素是指针类型,最后与int结合,说明指针所指向的元素是整形,所以p是一个由指向整形元素的指针组成的数组
int(*p)[3];//从p开始,先与*结合,是一个指针,再与[]结合,说明这是一个指向数组的指针,再与int结合,说明数组里的元素是整形的,所以p一个指向由整形元素组成的数组的指针,是数组指针
int** p;//从p开始,先与右边的*结合,说明是一个指针,再与左边的*结合,说明这是一个指向(左*)指针的(右*)指针,再与int结合,说明(左*)指针的返回类型是整形的,所以p是一个返回整型类型的指针的指针
int p(int);//从p开始,与int结合,说明是一个有一个整形变量参数的函数,再与左边的Int相结合,说明这个函数的返回类型是整形,说明p是一个返回整型类型且有一个整形变量参数的函数
int* p(int);//从p开始,与int结合,说明p是一个有一个整形变量参数的函数,再与*结合,说明这个函数的返回的是一个指针,再与int结合,说明这个指针的返回的是整形类型,所以这是一个返回的是一个整型类型指针的函数
int (*p)(int);//从p开始,与*结合,说明p是一个指针,再与int结合,说明是指向一个有一个整形变量参数的函数的指针,再与int结合,说明函数的返回类型是整形,所以p是一个指向一个返回整型类型且只有一个整形变量参数的函数的指针
int *(*p(int))[3];//从p开始,与int结合,说明指针指向的是一个有一个整型变量参数的函数,再与*结合,说明函数返回的是一个指针,再与外面的[]结合,说明指针指向的是一个数组, 再与*结合,数组里的元素是指针,再与int结合,说明p是一个返回指向一个返回类型为整型的指针类型组成的数组的指针的函数
这是绝大多数会用到的指针类型,如果上述指针类型都能够很好地理解了,其他的指针理解也就有了规律。
规律大致如下:
从语法的角度看,你只要把指针声明语句里的 指针名字 去掉,剩下的部分就是这个指针的类型。这是指针本身所具有的类型。for example:
char* p 的指针类型是 char*
char** p 的指针类型是 char**
int* p[3] 的指针类型是 int* ()[]
以此类推…
从语法上看,你只须把指针声明语句中的 指针名字和名字左边的指针声明符* 去掉,剩下的就是指针所指向的类型。
char* p 所指的指针类型是 char
char** p 所指的指针类型是 char*
int* p[3] 所指的指针类型是 int ()[]
以此类推…
sizeof
在学习操作符的时候,我们学习了 sizeof , sizeof 计算变量所占内存内存空间⼤⼩的,单位是字节,如果操作数是类型的话,计算的是使⽤类型创建的变量所占内存空间的⼤⼩。sizeof 只关注占⽤内存空间的⼤⼩,不在乎内存中存放什么数据。
#inculde <stdio.h>
int main()
{
int a = 10;
printf("%d\n", sizeof(a));
printf("%d\n", sizeof a);
printf("%d\n", sizeof(int));
return 0;
}
strlen
统计的是从 strlen 函数的参数 str 中这个地址开始向后, \0 之前字符串中字符的个数。
strlen 函数会⼀直向后找 \0 字符,直到找到为⽌,所以可能存在越界查找
#include <stdio.h>
int main()
{
char arr1[3] = {'a', 'b', 'c'};
char arr2[] = "abc";
printf("%d\n", strlen(arr1));
printf("%d\n", strlen(arr2));
printf("%d\n", sizeof(arr1));
printf("%d\n", sizeof(arr1));
return 0;
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。