AL控制组李鋆——指针学习笔记

一 .指针学习笔记

9.1-1 取地址运算:&运算符取得变量的地址

(1)&运算符

  • 这里的&指的就是scanf(“%d”,&i)里面的&
  • 获得变量的地址,它的操作数必须是变量
  • 地址的大小是否与int相同取决于编译器
  • 我们用要printf出一个变量的地址要这样干
//得用printf(“%p”,&i);而不是用printf(“%x”,&i)//
#include <stdio.h>
int main(void)
{
	int i=0;
	printf("%p",&i);
	return 0;
}

(2)相邻变量的地址

相邻两个变量相差4,原因就在于每个变量占四个字节,并且先定义的变量是更大的,究其原因就在于在堆码中内存分配是自上而下的
如图:在这里插入图片描述

(3)数组的地址

int a[10];
printf(“%p\n",&a)会等于printf(“%p\n”,a)也会等于a[0]的地址,同理数组中每相邻的两个变量的地址也会相差四。

#include <stdio.h>
int main(void)
{
	int a[10];
	printf("%p\n",&a);
	printf("%p\n",a);
	printf("%p\n",&a[0]);
	printf("%p\n",&a[1]);
	return 0;
}

这就是以上代码运行得到的结果

9.1-2 指针 :指针变量就是记录地址的变量

(1)指针

  • 作用:就是用来保存地址的变量

  • int i;
    int* p=&i;
    这个 * 的意思就是告诉你p是一个指针,然后我们把i变量的地址交给了p这个指针(也可以叫做p指向了i),这个 “*”可以远离int,也可以靠近int,都是一个意思哒。

  • 还有一个要注意的点就是定义两个指针时不能这样写
    int *p,q;
    这样q是没有被定义到的,应该这样写
    int *p,*q;

(2)指针变量

  • 普通变量的值是实际的值
  • 而指针变量的值是具有实际值的变量的地址,指针变量指向存有地址的普通变量

(3)作为参数的指针

  • void f(int *p) int i=0; f(&i)
    我们可以把变量 i 的值交给 f 函数中的 p 指针,这样在 f 函数里面我们就可以通过这个指针访问外面的这个 i 了,而通过简单的将 i 的值交给某一个 g 函数就做不到这些功能。
    我们用图像来描述会更加形象
    在这里插入图片描述

(4)访问那个地址上的变量*

  • *是一个单目运算符,用来访问指针的值所表示的地址上的变量
  • 其既可以做左值也可以做右值
    eg.int k=*p;
    *p=k+1;

在这里插入图片描述

在这里插入图片描述

(5)错误传入地址而没有报错

原因就在于scanf把你传入的实际值误认成了那个变量的地址,虽然编译没有报错,但运行一定会出错!!!

9.1-3指针的使用:指针有什么用?

(1)指针应用场景一——交换两个变量的值

eg.

#include <stdio.h>
 void swap(int *pa,int *pb);
 
 int main(void)
 {int a=3;
  int b=9;
  swap(&a,&b);//把下面调换的ab的地址重新调用到上面来//
   printf("a=%d b=%d\n",a,b);	
  return 0; 

 }
 void swap(int *pa,int *pb)
 {  int t=*pa;
    *pa=*pb;
    *pb=t;
    
 }

(2)指针引用场景二

  • 函数返回多个值时,某些值只能通过指针返回
  • 传入的参数实际上是需要保存带回的结果的变量
    eg.
    利用指针来遍历出一个数组中的最大最小值
#include <stdio.h>
void minmax(int a[],int length,int *max ,int *min);
int main(void)
{int min,max;
 int a[]={2,5,7,8,45,76,890,56};
 minmax(a,sizeof(a)/sizeof(a[0]),&max,&min);
 printf("min=%d max=%d",min,max);
 return 0;
}


void minmax(int a[],int length,int *max ,int *min)
{
	int i;
	*max=*min=a[0];
	for (i=1;i<length;i++)
	{
		if(a[i]>*max)
		{*max=a[i];
		}
		if(a[i]<*min)
		{*min=a[i];
		}
	}
}

(3)指针引用场景三——返回值

在平时我们都是让函数返回一些特殊值(像是-1,1,0)来让函数返回运算状态,
但当所有的值都有可能成为运算结果时,就得利用指针来进行函数返回了。
eg.当除法运算中分母为一时也能返回运算

#include <stdio.h>
int divide(int a,int b,int *result);
int main(void)
{int a=0;
 int b=0;
scanf("%d %d",&a,&b);
int c;
if (divide(a,b,&c))
{printf("%d/%d=%d\n",a,b,c);
}
return 0;
	
}
int divide(int a,int b,int *result)
{int ret=1;
 if(b==0)
 {ret=0;
 }
 else
 {*reslut=a/b;
 }
 return ret;
}

(4)指针使用的常见错误

在一个指针还未取得某个变量的地址时就对其赋值会导致程序崩溃

9.1-5 指针与const

(1)指针是const

  • 指针一旦得到了每个变量的地址,就不能再指向其他变量了
    eg.就像是int const q =&i,那么q就不能再接受其他的变量的地址了

  • 但是q=26等访问是可以进行的,因为q所指的int i并不是const

  • 再者q++,q–等运算就不能再进行了

(2)所指是const

  • 表示:const int *p=&i;
  • 它可以去指向其他的变量,获得其他变量的地址
  • int i 变量也可以去进行改变,比如说 i++,i=27;
  • 唯一不能做的就是通过p去改变 i 的值,即p=26 是不可以做的(通过指针不可修改)

(3)辨析题

int i;

  • const int*p1=&i;
  • int const *p2=&i;
  • int const p3=&i;
    技巧:只要
    在const的后面就是(1)情况,如果在后面的话就是(2)情况,指针不可修改。

(4)const数组

eg.const int a[]={1,2,3,4,5,6,7};

  • 数组变量已经是const的指针了,这里的const表明数组的每个单元都是const int
  • 这样const数组之后就表明数组中的每个int都被const了,像是a[0],a[1]这些都是不可以改变的。
  • 所以这个样子的数组就必须通过初始化来进行赋值。

(5)保护数组

在把数组传入函数的时候我们传入的是数组的地址,所以在函数中是可以改变数组的值的,所以为了保证数组的值不被改变我们就可以通过const数组(设置参数为const)
eg.int sum( const int a[ ] , int length);

9.2-1 指针运算

(1).先导(有关知识点)

-我们再指针上加 1 并不是在地址上加 1 ,而是在地址上加了个指针类型,你指针是int,你就在地址上加4,你是char的话就在上面加个 1
{ 注意:sizeof(char)=1,而sizeof (int)=4;}
在这里插入图片描述

#include <stdio.h>
int main (void)
{
	char ac[]={1,2,3,4,5,6,};
	char *p=ac;
	printf("p=%p\n",p);
	printf("p+1=%p\n",p+1);
	int ai[]={1,2,3,4,5,6,7,};
	int *q=ai;
	printf("q=%d\n",q);
	printf("q+1=%d\n",q+1);
	return 0;
}

在这里插入图片描述
用以上代码就可证明此结论
注意点:* 这个的运算级高于±号,所以我们在表示数组中的下一个数是要加一个括号呐
eg.*p——a[0]
*(p+1)——a[1]
可以用以下代码进行检验

#include <stdio.h>
int main (void)
{
	char ac[]={1,2,3,4,5,6,};
	char *p=ac;
	printf("p=%p\n",p);
	printf("p+1=%p\n",p+1);
	printf("*(p+1)=%p\n",*(p+1));
	int ai[]={1,2,3,4,5,6,7,};
	int *q=ai;
	printf("q=%d\n",q);
	printf("q+1=%d\n",q+1);
	printf("*(q+1)=%d\n",*(q+1));
	return 0;
}

(2). 指针计算

  • 可以给指针加减一个整数
  • 指针也可以进行递增递减
  • 两个指针还能相加减
#include <stdio.h>
int main (void)
{
	char ac[]={1,2,3,4,5,6,};
	char *p=ac;
	printf("p=%p\n",p);
	printf("p+1=%p\n",p+1);
	printf("*(p+1)=%p\n",*(p+1));
	printf("*(p+1)-*p=%d\n",*(p+1)-*p);//此行可证两个指针可以相减//
	int ai[]={1,2,3,4,5,6,7,};
	int *q=ai;
	printf("q=%d\n",q);
	printf("q+1=%d\n",q+1);
	printf("*(q+1)=%d\n",*(q+1));
	return 0;
}

但要注意的是相减得到的不是地址数的差值,而是 差值/每个变量对应的字节数

(3).有关*p++的内容

  • 可以先去除p所指的那个数据,完事之后顺便把p移到下一个位置上去
  • *星号的运算级虽然高,但是没有++运算级高
  • 常用于数组类的连续操作(也就是有了一种新的遍历数组的方法)
    如下
#include <stdio.h>
int main (void)
{
	char ac[]={1,2,3,4,5,6,-1};//可以在数组的最后放上一个不可能取到的数//
	char *p=ac;
	while(*p!=-1)
	{printf("%d ",*p++);
	}
	return 0;
}
	

(4).指针比较

  • <,<=,==…这些都可以对指针进行
  • 但比较的是他们在内存中的大小(就是比较地址的数值)
  • 还有就是数组中的单元肯定是线性递增的

(5). 0地址

  • 0地址一般是不能碰的,也不干活的,所以可以用0地址来干一些特殊的事情
    eg.返回的指针是无效的;指针没有被真正初始化(先初始化为0)

  • NULL是一个预先定义的符号,表示)地址,所以以后尽量用NULL(必须大写)来表示0地址

指针的类型

  • 无论是什么类型的指针,其大小都是一样的,因为都是地址
  • 但是指向不同的指针是不可以相互赋值的,这是为了避免用错指针
    就比如说你让
char *a;
 int *b;
 *a=*b;

这样程序是运行不了的,原因就在于指针的大小是统一的,但是每一种变量的字节是不一样的呀!!!

(6).指针类型转换(初学者不建议这么干)

  • void*可以用来表示不知道指向什么的指针(计算时与char相同,但是不相通哈)
  • 指针类型转换
    像这个样子呐 int *p=&i;void q=(void)p;

(7).小结 -指针可以用来干神马

  • 需要传入较大的数据是用作参数

  • 传入数组后对数组做操作

  • 函数返回不止一个结果

    • 需要用函数来修改不止一个变量
  • 动态申请的内存…

9.2-2 动态内存分配

(1).malloc(做的事情就是跟系统要块内存来)

  • 要这个头文件
    #include <stdlib.h>
    向malloc申请空间的大小是以字节为单位的
    void * malloc(size_t size);
    返回的结果是void*,需要类型转换为自己需要的类型
    (int*)malloc(n*sizeof(int))
  • 空间不足的话就会输出NULL(0位置)
#include<stdio.h>
#include <stdlib.h>
int main(void)
{
	int count =0;
	void *p;
	while((p=malloc(100*1024*1024)))
	{count++;
	}
    printf("分配了%d00MB的空间\n",count);
    return 0;

}
//可以看一下用自己的电脑能分配到多少空间//

(2).free()

  • 得把申请得来的空间还给系统
  • 只能还申请来地空间的首地址

(3).常见问题

  • 申请了没有free()——长时间运行内存逐渐下降
  • free过了再free
  • 地址变过了,直接去free

//啊累死了累死了//

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值