C指针笔记

变量实质

声明两个变量,其中整形变量i占两个字节,字符型a占一个字节。

int i;
char a;

实际在内存中的映像如图
在这里插入图片描述

变量赋值

赋值给变量,即是将该值赋给相应的地址中

i=30;
a='t';

在这里插入图片描述
如此,我们可以通过代码打印查看变量与它的地址

#include<stdio.h>
int main ()
{
	int i = 39;
	printf ("%d\n" , i);/*i*/
	printf ("%d\n", &i) ;/*i的地址*/
	return(0) ;
}

在这里插入图片描述

指针

声明指针变量pi

int *pi;

则内存映射为
在这里插入图片描述
可以看出pi不过是在内存的某个地方声明一个一定宽度的内存空间
将变量i的地址编号赋给pi指针

pi=&i;//i的地址为6、7

在这里插入图片描述
现在的情况就是:i是一个变量,pi指向了变量i,pi是i变量的地址编号相当于&i,而*pi则是读取i的存储的地址的值。
使用代码打印进行对比

#include<stdio.h>
int main ()
{
	int i = 39;
	int *pi;
	pi=&i;//i的地址为6、7
	printf ("--值--\n", &i) ;
	printf ("%d\n" , i);/*i*/
	printf ("%d\n", *pi) ;
	printf ("--地址--\n", &i) ;
	printf ("%d\n", &i) ;/*i的地址*/
	printf ("%d\n", pi) ;
	return(0) ;
}

在这里插入图片描述
所以我们可以通过改变指针pi来改变所指的地址内的变量值。

char a , *pa;
a=10;
pa = &a;
*pa = 20;

通过数组名访问数组元素

使用数组名(首地址)和普通方式访问数组元素,效果一致

#include<stdio.h>
int main ()
{
	int i, a[] = { 3,4,5,6,7,3,7,4,4,6};
	for (i = 0; i <=9; i++)
		printf("%d\n", * (a+i) );
	printf("--数组元素--\n");
	for (i = 0; i <=9; i++)
		printf("%d\n", a[i] );
	return(0) ;
}

在这里插入图片描述

字符串数组

#include<stdio.h>
void to(char *array)
{
	for(int i=0;*(array+i)!=0;i++)
	{
		if(*(array+i)==0)
		{	
			break;
		}
		else
		{
			printf("%c",*(array+i));
		}
	}
	printf("\n");
	
}
main()
{
	char str[] = { "afsdfsdfdf\O"};/*待查找的字符串 */
	to(str);/*调用函数以实现所要操作。*/
	printf("%s\n",str);
	return(0);
}

通过指针访问数组元素

#include<stdio.h>
int main ()
{
	int i, *pa,a[] = { 3,4,5,6,7,3,7,4,4,6};
	pa=a;
	for (i = 0; i <=9; i++)
		printf("%d\n", pa[i] );
	printf("--赋值数组名--\n");
	for (i = 0; i <=9; i++)
		printf("%d\n",*(pa+i) );
	return(0) ;
}

在这里插入图片描述

数组名与指针变量的区别

数组名与指针变量还是有所区别的,数组名只是一个指针常量,而指针是指针变量。

#include<stdio.h>
int main ()
{
	int i,*pa,a[]= {3,4,5,6,7,3,7,4,4,6};
	pa =a;
	for (i = 0; i <=9; i++)
	{
		printf("%d\n",*pa);
		pa++;/*注意这里,指针值被修改*/
	}
	return(0) ;
}

上述代码中,pa换成a是无法正常编译的

const int i

const声明定义的称为符号常量,后期不能进行修改其值。有两种写法:

const int ic = 20;//等同于
int const ic = 20;

const定义的*pi是不可修改的,但是pi是可以修改的

#include<stdio.h>
int main ()
{
	int il = 30;
	int i2 = 40;
	const int *pi = &il;
	pi = &i2;/*注意这里,pi可以在任意时候重新赋值一个新内存地址*/
	i2 = 80;/*想想看:这里能用*pi = 80来代替吗?当然不能!*/
	printf("%d\n",*pi);
	return(0);
}

int *const pi与int const *pi

int *const pi,可以改变*pi,不能改变pi
int const *pi,可以改变pi,不能改变*pi
#include<stdio.h>
int main ()
{
	int il = 30;
	int i2 =40;
	int *const pi = &il;

	/* 不能pi = &i2;即不能再指向另一个新地址。*/

	il = 80;/*可以用*pi = 80;来代替,可以通过*pi修改i1的值。*/
	
	printf("%d",*pi);/*输出是80*/
	return(0);
}

声明为常量的pi,将无法通过其他方式进行修改,定义其他指针变量去改对应地址的值也行不通。

函数参数传递

第一种:值传递

#include<stdio.h>
void Exchg1 (int x, int y)
{
	int tmp;
	tmp =x;
	x = y;
	y = tmp;
	printf ("x = %d,y = %d\n",x, y);
}
main()
{
	int a = 4,b= 6;
	Exchg1(a, b);
	printf("a = %d, b = %d\n", a, b);
	return(0);
}

在这里插入图片描述
这是因为函数形参实参之间传递的是:

int x=a;
int y=b;

仅仅是将a、b的值赋给x、y,并没有对a、b进行本质上的改变。

第二种:地址传递

#include<stdio.h>
void Exchg2 (int *px, int *py)
{
	int tmp = *px;
	*px = *py;
	*py = tmp;
	printf ("*px= %d,*py = %d\n",*px,*py);

}
main()
{
	int a = 4,b= 6;
	Exchg2(&a, &b);
	printf("a = %d, b = %d\n", a, b);
	return(0);
}

在这里插入图片描述

int *px=&a;
int *py=&b;

这样,就使得px、py两个指针变量指向了a和b地址,而通过修改他们的值,就能够修改a和b的值了。

第三种:引用传递

#include<stdio.h>
void Exchg3 (int &x, int &y)
{
	int tmp = x;
	x = y;
	y = tmp;
	printf ("x= %d,y = %d.\n",x,y);

}
main()
{
	int a = 4,b= 6;
	Exchg3(a, b);
	printf("a = %d, b = %d\n", a, b);
	return(0);
}

在这里插入图片描述

int &x=a; 
int &y=b;

这样就代表,x、y直接引用了a、b变量,也就是直接当做实参本身来使用了。

指针的指针

short int i;
char a; 
short int * pi;
a = 7;
i = 50; 
pi = &i;

加粗样式

short int **ppi; /* 这是一个指向指针的指针,注意有两个“*”号*/ 
*ppi = &pi;

在这里插入图片描述
所以,ppi=pi的地址,9。*ppi=5,**ppi=50。

指针的指针实例代码

(1)设计一个函数: void find1(char array[],char search,char *pa)
要求:这个函数参数中的数组array是以О值为结束的字符串,要求在字符串array 中查找字符是参数search里的字符。如果找到,函数通过第三个参数(pa)返回值为array字符串中第一个找到的字符的地址。如果没找到,则为pa为0。
#include<stdio.h>
void find1 (char array[], char search,char *pa)
{
	int i;
	for (i= 0;* (array + i)!= 0;i++)
	{
		if(* (array+i)== search)
		{
			pa=array + i ;
			break;
		}
	}
}
main()
{
	char str[] = { "afsdfsdfdf\O"};/*待查找的字符串 */
	char a = 'd' ;/*设置要查找的字符*/
	char *p = 0;/* 如果查找到后指针p将指向字符串中查找到
	的第1个字符的地址。*/
	find1(str, a, p);/*调用函数以实现所要操作。*/
	if(0 == p)
	{
		printf("没找到!\n");/*如果没找到则输出此句*/
	}
	else
	{
		printf("找到了,p = %d", p);/*如果找到则输出此句*/
	}
	return(0);
}

此处,仍然是使用值传递的方式,pa=p,所以不会使p发生改变。
正确的应该是这样写

#include<stdio.h>
void find1 (char array[], char search,char **ppa)
{
	int i;
	for (i= 0;* (array + i)!= 0;i++)
	{
		if(* (array+i)== search)
		{
			*ppa=array + i ;
			break;
		}
		else if(* (array+i)==0)
		{
			*ppa = 0;
			break;
		}
	}
}
main()
{
	char str[] = { "afsdfsdfdf\O"};/*待查找的字符串 */
	char a = 'd' ;/*设置要查找的字符*/
	char *p = 0;/* 如果查找到后指针p将指向字符串中查找到
	的第1个字符的地址。*/
	find1(str, a, &p);/*调用函数以实现所要操作。*/
	if(0 == p)
	{
		printf("没找到! n");/*如果没找到则输出此句*/
	}
	else
	{
		printf("找到了,p = %d", p);/*如果找到则输出此句*/
	}
	return(0);
}

函数名与函数指针

示例函数指针声明方法

void (*FunP)(int);

n种函数调用方法

#include<stdio.h>

void MyFun (int x);/*这个声明也可写成: void MyFun( int )*/
void (*FunP)(int);/*也可声明成void(*FunP)(int x),但习惯上一般不这样。*/

int main (int argc, char *argv[ ])
{
	MyFun (10);/*这是直接调用Myun函数*/
	FunP =&MyFun;/*将MyFun函数的地址赋给FunP变量*/
	//FunP = MyFun; /*将MyFun函数的地址赋给FunP变量 */
	//(*MyFun)(10);
	(*FunP)(20);/*这是通过函数指针变量FunP来调用MyFun函数的。*/
}

void MyFun (int x)/*这里定义一个MyFun函数*/
{
	printf( "%d\n" ,x);
}

MyFun 的函数名与 FunP 函数指针都是一样的,即都是函数指针。但是MyFun 函数名是一个函数指针常量,而 FunP 是一个函数数指针变量。

  1. FunP 函数指针变量可以如“ (*MyFun)(10) ”这样调用,也可以 “ FunP(10) ”的形式来调用
  2. 赋值时,即可“ FunP = &MyFun ” 形式,也可“ FunP = MyFun ”。
  3. 在函数的声明处:
    void MyFun(int); //不能写成 void (*MyFun)(int)。
    void (*FunP)(int); //不能写成 void FunP(int)。

定义某一函数的指针类型

#include<stdio.h>

void MyFun(int x); /*此处的声明也可写成:void MyFun( int )*/ 
typedef void (*FunType)(int); /*这样只是定义一个函数指针类型*/ 
typedef int* PINT; /* 为 int* 类型定义了一个 PINT 的别名*/

FunType FunP; /*然后用 FunType 类型来声明全局 FunP 变量*/ 
int main(int argc, char* argv[]) 
{ 
	FunType FunC; /*函数指针变量当然也是可以是局部的 ,那就请在这里声明了。 */ 
	MyFun(10); 
	FunP = &MyFun; 
	(*FunP)(16);
	return 0; 
} 
void MyFun(int x) 
{ 
	printf("%d\n",x); 
}

函数指针作为某个函数的参数

#include<stdio.h>

void MyFun1(int x); 
void MyFun2(int x); 
void MyFun3(int x); 
typedef void (*FunType)(int ); /*定义一个函数指针类型*/

void CallMyFun(FunType fp,int x);
int main(int argc, char* argv[]) 
{ 
	CallMyFun(MyFun1,10); /*通过 CallMyFun 函数分别调用三个不同的函数 */ 
	CallMyFun(MyFun2,20); 
	CallMyFun(MyFun3,30); 
} 

void CallMyFun(FunType fp,int x) 
{ 
	fp(x);
} 
void MyFun1(int x) 
{ 
	printf("函数 MyFun1 中输出:%d\n",x); 
}
void MyFun2(int x) 
{ 
	printf("函数 MyFun2 中输出:%d\n",x); 
} 
void MyFun3(int x) 
{ 
	printf("函数 MyFun3 中输出:%d\n",x); 
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值