C语言之浅谈指针
1.指针是什么?
>指针 :是编程语言中的一个对象,利用地址。它的值直接指向存在电脑储存器中另一个地方的值。通俗的说就是地址
>指针变量:就是变量里面放的是地址
>变量指针:变量的地址
如:
int main(){
int a=10; //在内存中开辟一块空间
int *p=&a; //对变量a取出它的地址,可用&操作符。将a的地址放在p变量中,p就是一个指针变量
return 0;
}
补充:存在指针中的值都被当作地址处理
2.为什么存在指针?
>指针是存放地址才出现的,地址是为了标示一块地址空间
>指针让地址有地方存放,指针让内存的访问跟方便
>指针的大小在32位平台下是4个字节,在64位平台下是8个字节
3.指针和指针类型
>指针的类型是:type+*的方式
如:
char *pc=NULL;
int *pi=NULL;
short *ps=NULL;
long *pl=NULL;
float *pf=NULL;
double *pd=NULL;
type *类型的指针是为了存放type类型变量的地址。
>为什么有指针类型?
只要有类型的区分,就定出一定的规则,是的编码会更加的严谨。
确定了指针运算的规律。
>指针类型如何确定指针运算的规律?
(1)指针+-整数
#include<stdio.h>
int main(){
int n=10;
char *pc=(char*)&n; //指向n的低字节
int *pi=&n;
printf("%p\n",&n);
printf("%p\n",pc);
printf("%p\n",pc+1); //加类型的字节大小
printf("%p\n",pi);
printf("%p\n",pi+1); //加类型大小
}
运行结果:
总结:指针类型决定了指针向前或者向后走一步有多大。
(2)指针的解引用
int main(){
int n=0x11223344;
char *pc=(char *)&n;
int *pi=&n;
*pc=0x55; //这时n变为0x11223355,因为char只占一个字节,所以直接替换最低位
*pi=0; //这里的0是0000……00
return 0;
}
总结:指针的类型,决定了对指针解引用时访问的字节数。3.二级指针:
>在下面代码中,a的地址存放在pa中,pa的地址存放在ppa中。pa是一级指针,ppa是二级指针
int a=10;
int *pi=&a;
int **ppa=&pa;
画图详解;
>二级指针运算:
*ppa通过对ppa中的地址进行解引用,这样找到的是pa。
**ppa通过ppa找到pa,然后对pa进行解引用操作:*pa找到的是a。
**ppa =30;
//等价于*pa=30;
//等价于a=30;
4.表达式解析:
给定下面代码:
char ch='a';
char *cp=&ch;
下面代码是否可以做左值或右值:(使用变量的存储空间)=(使用变量的内容)
&ch; //&ch取地址常量,不能做左值,但可以做右值。
cp; //cp是变量,可以做左值,可以做右值。
&cp; //&cp是地址常量,不能做左值,可以做右值。
*cp+1; //*cp+1表达式的结果是常量,不能做左值,可以做右值。
*(cp+1); //*(cp+1)表示cp之后的一块空间,可以做左值,也可以做右值。
++cp; //在C中前置++不能做左值,可以做右值。
cp--; //在C中后置++不能做左值,可以做右值。
*++cp; //是ch下一块空间,可以做左值也可以做右值。
*cp++; //++是后置,所以*cp++可以做左值,也可以做右值。
++*cp; //表达式是对*cp后置++,不能做左值,可以做右值。
(*cp)++; //表达式是对*cp后置++,不能做左值,可以做右值。
++*++cp; //表达式是对下一块空间的内容前置++,所以表达式不能做左值,可以做右值。
++*cp++; //表达式是对ch内容的前置++,同时也对cp进行后置++,所以表达式不能做左值,可以做右值。
5.指针运算:
>指针+-整数:
#include<stdio.h>
#define N 5
int main(){
float f[N];
float *p;
for(p=&f[0];p<&f[N];){
*p++=0;
}
}
数组清零,从前往后清零>指针-指针:
int my_strlen(char *s){
char *p=s;
while(*p!='\0'){
p++;
}
return p-s;
}
返回字符串长度>指针的关系运算:
#include<stdio.h>
#define N 5
int main(){
float f[N];
float *p;
for(p=&f[N-1];p>=&f[0];p--){
*p=0;
}
}
从后往前清零。
标准规定:允许向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。
6.相关练习:
>将一个数组中的数据反向顺序输出:
如int a[10]={1,2,3,4,5,6,7,8,9,0};
则输出为a[10]={0,9,8,7,6,5,4,3,2,1};
代码如下:
#include<stdio.h>
#include<assert.h>
void reverse(int *a,int size){
assert(a);
int *start=a;
int *end=a+size-1;
while(start<end){
*start^=*end;
*end^=*start;
*start^=*end;
start++;
end--;
}
}
int main(){
int a[10]={1,2,3,4,5,6,7,8,9,0};
int size=sizeof(a)/sizeof(a[0]);
reverse(a,size);
for(int i=0;i<size;i++){
printf("%d ",a[i]);
}
}
定义两个指针变量,一个指向数组头部,一个指向数组尾部,两指针交换,然后向中间移动,结束条件是strart>=end.
>分别用数组和指针两种方式对十个整数由大到小排序。
用数组冒泡法:
#include<stdio.h>
#include<assert.h>
void bubble_sort(int a[],int size)
{
assert(a);
int i=0;
for(;i<size-1;i++){
int j=0;
int flag=0;
for(;j<size-1-i;j++){
if(a[j]>a[j+1]){
a[j]^=a[j+1];
a[j+1]^=a[j];
a[j]^=a[j+1];
flag=1;
}
}
if(flag==0)break; //用来判断传进来的数组是否是有序数组
}
}
int main(){
int a[10]={2,3,1,4,5,34,7,8,6,8};
int size=sizeof(a)/sizeof(a[0]);
bubble_sort(a,size);
for(int i=0;i<size;i++){
printf("%d ",a[i]);
}
}
用指针冒泡:
#include<stdio.h>
#include<assert.h>
void bubble_sort(int *a,int size)
{
assert(a);
int *start=a;
int *end=a+size-1;
while(end>a){
int flag=0;
for(start=a;start<end;start++){
if(*start>*(start+1))
{
*start^=*(start+1);
*(start+1)^=*start;
*start^=*(start+1);
flag=1;
}
}
if(flag==0)break;
end--;
}
}
int main(){
int a[10]={2,3,1,4,5,34,7,8,6,8};
int size=sizeof(a)/sizeof(a[0]);
bubble_sort(a,size);
for(int i=0;i<size;i++){
printf("%d ",a[i]);
}
}
定义两个指针,一个指向数组首地址start,一个指向数组尾地址end,循环n次则进行n-1次比较,start用来进行比较,end来控制每次循环的次数。上一篇: thinkPHP实现签到功能的方法