指针(学习笔记)

1指针相关概念

1.1地址与指针

地址是变量在内存中的位置,指针就是地址。

在程序中定义一个变量,编译时程序会给变量在内存中分配一个地址,通过访问这个地址,就可以找到该变量,这个地址就成为该变量的指针。

1.2变量与指针

变量的地址是变量与指针的纽带。所谓“指向”就是把一个变量的地址赋给了一个指针。当把变量x的地址存到指针p中时,就说指针p指向变量x

1.3指针变量

指针变量:这个变量专门存放别的变量的地址

1.指针变量的一般形式:    类型名 * 变量名  如 int *p或 int* p    两种形式一样

2.指针变量的赋值

(1)

int a;

int *p = &a;

“&”是取地址符号,&a表示a的地址 

(2)

int a;

int *p;

p=&a;

注意:不能直接把数据赋给指针

3.指针变量的引用

比如  

int a=5;

int *p=&a;

printf("%d",*p);               //引用指针变量

用的时候就直接    “  *指针变量   ”

4.& 与 *

&叫取地址运算符,是取地址符号,返回变量的地址。

*叫指针运算符,是取数据的符号,返回变量的值。

它俩的运算符优先级别相同,且都是从右到左。

所以   &*p是先算*,*p是a;再算&,取*p(也就是a)的地址,表示取a的地址

*&a 先算&,取a的地址,再算*,取a所在地址上的数据。

1.4指针的运算

指针是地址,所以指针的自加自减不是简单的在数值上+1或-1,而是+1个地址或-1个地址

比如  

int *p;

p++;

p--;

p是int 类型的,int内存大小是4字节,所以p++是p的值增加了1*4=4;p--是p的值减了1*4=4.

当两个指针p1,p2都指向同一数组中的元素,p2-p1=(p2地址-p1地址)/数组长度;如p2指向a[5]地址为2020,p1指向a[3]地址为2012,两指针都是int 类型,p2-p1=(2020-2012)/4=2.

其意义是p2所指元素与p1所指元素之间相差2个元素。

这样可以直接算出两元素的相对位置。

2.数组与指针

2.1 一维数组与指针

(1).

int *p,a[10];

p=a;

这样指针p就指向了数组a,因为在数组中,数组名称a就是数组在内存中的首地址,所以p=a中不需要“&”。

int *p;a[10];

p=&a[0]

将数组a的首个元素的地址赋给p,这与前面的等价,p=a,p指向的也是数组a的首个元素 

对于数组中其他元素

*(p+i)等价于*(a+i)等价于a[i]

p+i与a+i都可以表示数组中各元素的地址

(2). 

可以先让指针p指向数组中的一个元素,之后想让p指向下一个元素时,直接用“p++”(同理,指向上一个元素可以用“p--")

如:

#include<stdio.h>
int main ()
{
	int a[5]={1,2,3,4,5};
	int *p;
	for(p = a;p < (a+5);p ++)
	printf("%d  ",*p);
	 return 0;
}

但是,如果不用p而用数组名a的变化去指向不同元素是不行的

for(p = a;p < (a+5);a ++)
    printf("%d  ",*a); 

因为数组名a代表数组首个元素的地址,它是个指针型常量,在程序运行的过程中是固定不变的,因此a++无法实现。

注意,在使用这种方法时要注意指针的当前位置。

错误案例:

#include<stdio.h>
int main ()
{
	int a[5],i,*p;
	p=a;                 //p指向a[0] 
	for(i = 0;i < 5;i ++)
	scanf("%d",p++);     //输入整数给a[0]~a[4]
	
	for(i = 0;i < 5;i++,p++)
	printf("%d\n",*p);   //想输出a[0]~a[4]
	
    return 0;
}

 

 这是因为在第一个for循环结束时,p指向的是数组中的最后一个元素a[4],当第二个for循环时,p的起始值不是&a[0]了,所以执行p++时,p指向的是数组a后面的存储单元,但这些存储单元的值是不知道的。

解决办法是在两个for循环中间加一句  p=a   使p重新指向&a[0]

正确案例:

#include<stdio.h>
int main ()
{
	int a[5],i,*p;
	p=a;                 //p指向a[0] 
	for(i = 0;i < 5;i ++)
	scanf("%d",p++);     //输入整数给a[0]~a[4]
	
	p=a;                 //p重新指向a[0]
	
	for(i = 0;i < 5;i++,p++)
	printf("%d\n",*p);   //输出a[0]~a[4]
	
    return 0;
}

 

 

2.2二维数组和指针

表示二维数组地址的方法:

1). &a[0][0]可以看作数组第0行第0列的首地址,也可以看做二维数组的首地址。&a[m][n]是第m行第n列的元素的地址。

2). a[0]+n表示第0行第n个元素的地址

3). &a[0]是第0行的首地址,同理,&a[m]是第m行的首地址。

4).a+n表示第n行的首地址

用指针引用二维数组中的元素:

1). *(*(a+n)+m)第n行第m列的元素

2). *(*a[n]+m)第n行第m列元素

2.3字符串与指针

访问字符串的方式有两种,一种是用数组存放字符串;另一种就是用指针。

​
#include<stdio.h>
int main ()
{
     char *str="hello";
     printf("%s",str);    //输出字符串
}

​

这里定义了一个字符型指针变量 str,用字符串常量 hello 赋值给它。不过这里不是把  hello 都存到了str里,只是把 hello 的第一个字符的地址赋给str。

char *str="hello"; 

等价于

char *str;

str="hello";

2.4字符串数组

对于字符串数组可以用二维数组,也可以用一维指针数组。

如:二维数组

 char country[5][20]=
     {
         "China",
         "Japan",
         "Russia",
         "Germany",
         "Switzeriand"
     } 

这个数组5行20列,5个字符串,给每个字符串分配了20个字节空间,但每个字符串长度都小于20个字节,会造成空间上的浪费。

指针数组:一个数组,其元素都相当于指针变量。

定义形式: 类型名  数组名[数组长度]     (如果在定义数组时直接进行初始化,将数据存到了数组里,数组长度可以像下面例子那样不写)

#include<stdio.h>
int main ()
{
	int i;
     char *country[]=
	 {
	 	"China",
	 	"Japan",
	 	"Russia",
	 	"Germany",
	 	"Switzeriand"
	 };
	 for(i = 0;i < 5;i ++)
	 printf("%s\n",country[i]);
	 return 0;
}

3.指针变量作为函数参数

在C编译中,函数中的形参数组名是被当作指针变量来处理的

int fun(int arr[ ], int n)

等价于

int fun(int *arr, int n)

另外,C语言中实参和形参的数据传递是单向的“值传递”,只能将数据从实参传到形参。

指针变量传递的是实参数组首元素的地址;可以通过改变实参指针变量所指变量的值来改变实参数组的值

比如:

错误案例:交换x,y的值

#include<stdio.h>

void swap(int a,int b)
{
	int tmp;
	tmp=a;
	a=b;
	b=tmp;
}
int main()
{
     int x=1,y=2;
     swap(x,y);
     printf("%d %d",x,y);
}

因为单向传递,所以 没能成功

正解:

 

#include<stdio.h>

void swap(int *a,int   * b)//&x对应*a &y对应*b 
{
	int tmp;               //改变实参指针变量所指的变量的值 
	tmp=*a;                // 交换*a,*b 
	*a = *b;
	*b=tmp; 
}
int main()
{
     int x=1,y=2;
     swap(&x,&y);
     printf("%d %d",x,y);
}   

地址没变,变得是地址上的值。

4指针函数

返回值类型为指针类型的函数

定义形式:   类型名  *函数名(参数表列)

如:int *per(int a,int b);  

个人感觉没什么讲的,直接上例子:输入长方形的长和宽,求周长

#include<stdio.h>

int *per(int a,int b);          ——定义了一个返回指针值的函数
int Perimeter;

void main ()
{
	int iwidth,ilength,*iresult;
	printf("please input long:\n");
	scanf("%d",&ilength);
	printf("please input wide:\n");
	scanf("%d",&iwidth);
	iresult=per(iwidth,ilength);
	printf("长方形的周长是:");
	printf("%d\n",  * iresult); 
}

int *per(int a,int b){
	int *p;
	p=&Perimeter;
	Perimeter=(a+b) *2;
	return p;                 ——将存放周长的指针变量返回
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值