C语言指针详解附额外内容

格式说明符

%d 有符号十进制数
%o 8进制数
%x 16进制数
%c 字符
%s 字符串
%u 无符号10进制数

%m.nf m是宽度(或者理解为长度),n是保留小数点后n位数 
%md   m是宽度(或者理解为长度)
%0m字母 如果数字的长度不足则在空位补0

#include<stdio.h>
int main(int argc,char *argv[])
{
	float n=323.42;
	printf("%010.1f",n);输出“000000323.4”6个0+3个数字+小数点=10
        printf("%10.1f",n);输出“      323.4”6个空格(前)+3个数字+小数点=10
        printf("%-10.1f",n);输出“323.4      ”6个空格(后)+3个数字+小数点=10
	return 0;

}

while循环 

以前理解的while循环就是一个for,实际上其实就是这样的。真正理解上出问题的是进入循环的条件,计算机内部只存在0和1。而进入循环的条件:不是0就in,是0就out。

这也是我在刚开始看到 while(scanf("%d", &num))的时候一脸懵逼,输入的值非0就in,0就out。

while(任意语句)任意语句当然包括赋值语句
               

while(scanf("%d", &num))

 while(*to=*from)

#include<stdio.h>
int main(int argv,char *argc[])
{
	int i;   根据这个例子可以看出%d读入的0
                 无法进入while,%c读入的0==ASCii->48
                  就能进入while
	//char i;
	scanf("%c",&i); 
	//scanf("%d",&i);
	while(i)
	{
		printf("YES");
	} 
return 0;
}
 

  while(scanf("%d", &num))所以这个循环退出的条件就是输出0

数组与指针 

个人用语1.场地:计算机会在RAM里开辟内存给程序使用,便于理解把这些内存称之为场地

               2.room(房间):在这块场地里,每个数据们会被分配到一个小空间里,同样的理由称之为room

指针就是地址,地址就是指针

int* p;指针存储的是一个地址 int则是指针p的基类型。
       标明这是一个指向int数据的指针
int a=3;
p=&a;  把a的地址付给p
int b=*p *在原型声明之外是“取内容运算符”
         把指针p指向的地方(a)存储的内容(3)赋值给b
       

指针是计算机间接访问的利器-->指针指向谁,就能对谁进行各种操作,例如接下来的多级指针

自定义函数调用完后内存释放自定义函数区导致该区域数据全部free了例如经典的swap程序

#include<stdio.h>
void swap(int x,int y);
int main(int argc,char *argv[])
{
	int a=3,b=4;
	swap(a,b);
	printf("a=%d,b=%d",a,b);输出的结果a=3,b=4
return 0;
}                       

void swap(int x,int y) //调用swap函数时,计算机会在RAM开辟新场地给swap使用                        
{                      swap就会在这个新场地里做事情在swap调用完,RAM会把场地清空给其他人使用。
                        所以swap之前在这个新场地里做的事情也随之灰飞烟灭了
	int t;
	t=x;
	x=y;
	y=t;
}
                       

 

指针的出现就是为了解决这个问题 

#include<stdio.h>
void swap(int* x,int* y);
int main(int argc,char *argv[])
{
	int a=3,b=4;
	swap(&a,&b);
	printf("a=%d,b=%d",a,b);这里a和b就发生了交换
return 0;
}

void swap(int* x,int* y)//虽然swap一样在使用完后就会被free掉但是指针
{                       直接对原产地的a,b进行操作。即使swap消失了    
	int t;          指针的光辉事迹也还是被流传了下来
	t=*x;
	*x=*y;
	*y=t;
}

 

一维数组指针

#include<stdio.h>
int main(int argc,char *argv[]) //在设置一个数组的同时,
{                               //数组a的首地址会赋值给a
	int a[2]={0,1};
        int* p=a;
	printf("%d\n",a);  //a[0]地址
	printf("%d\n",*a); //a[0]的内容
	printf("%d\n",a+1);//a[1]的地址
	printf("%d\n",*(a+1));//a[1]的内容
        return 0;
}




a是一个const的指针!!!实际上是const int a[2];但是因为历史原因const被丢掉了。

 

判断

指针是否发生了移动

a+1(×) a++(无意义)a是const的指针,指针运算对它无意义  p=p+1(√)  

讲到这个就要说一说指针运算了,这章开头提到的基类型还有印象吗?(没有就往上翻一下)

例如int* p; p++那么p就会指向下一个int数据(运行上面的程序进行理解)

二维数组指针

在二维数组的指针a与一维数组的指针a不太一样。

多维数组指针与常规指针有所不同,将它称之为行指针。一段代码仔细研究比对发现它们的不同

2020/2/25隔了这么久才来补充二维数组指针,二维数组说是一个n*n的矩阵其实是便于理解。而事实上并不是这样的。例如一个3*4的二维数组,在内存中的分配其实3个有4个元素的一维数组构成 ,知道这一点对于二维数组指针应该会好理解很多。

int array[3][4];
#include<stdio.h>
int main(int argc,char *argv[])
{       一维数组-->一维数组指针a与*a 
	int a[2]={0,1};
	int* p=a;
	printf("a=%d\n",a);
	printf("p=%d\n",p);
	printf("*a=%d\n",*a);
	printf("*p=%d\n",*p);
        二维数组-->行指针a与*a
        int s[3][3]={{0,1,2},{3,4,5},{6,7,8}};
	int *p=s[0];
	int (*q)[3]=s;这是一个指向一行有3个元素的指针——>行指针
                      PS:q的基类型是int(*)[3]
        printf("p=%d\n",p);p是一个一维数组指针	
	printf("a[0]=%d\n",a[0]);
	printf("*a=%d\n",*a);行指针
	printf("a=%d\n",a);行指针
	printf("q=%d\n",q);行指针	
	printf("*q=%d\n",*q);行指针
	return 0;
}

 二维数组中的行指针与一维数组指针の某一元素引用

 需要先自行了解二维数组是如何在RAM中开辟场地的。 

#include<stdio.h>
int main(int argv,char *argc[])
{
	int a[3][3]={{0,1,2},{3,4,5},{6,7,8}};
	int *p=a[0];
	int (*q)[3]=a;
	 
	printf("%d\n",*(*(q+1)+1)); 使用行指针先*(q+i)获得第i+1行地址
                                    然后+j使指针指到i+1行第j个元素
	                            再用*把这个room里的值取出来  
	printf("%d\n",*(p+4));使用一维数组指针需要计算该元素离p地址的距离 

        return 0;
}

指针与字符串

设置一个字符数组然后通过指针操作,这与指针与数组一样。这里就不做赘述了。稍微讲一讲一种新的字符串指针

#include<stdio.h>
int main(int argc,char *argv[])
{
	const char* str="Hello World!";
        注意这个const,没有这个const。编译器会给你一个warning.通过这个warning容易得,这样的
        一个字符串是only read。
	printf("%s\n",str);比较输出结果理解str是什么
        printf("%s\n",str+2);
return 0;
}

函数指针

如何定义一个函数指针??

类型名(*指针名)(函数参数表列)   int(*p)(int x,int y);

1.在使用函数指针前必须先给它赋值

2.在赋值时只需给出函数名,不需要给出参数。

3.函数指针在调用函数时只需要(*指针名)代替函数名,后面的参数照旧

4.函数指针再调用函数时非常灵活,下面的一个例子来说明

输入1or2,输入1则输出a+b的值 ,输入2则输出a-b的值

#include <stdio.h>
int max(int,int);	
int min(int x,int y);	
int (*p)(int,int);	
int main(int argc,char* argv[])
{	
	int a,b,c,n;
	printf("please enter a and b:");
	scanf("%d,%d",&a,&b);
	printf("please choose 1 or 2:");
	scanf("%d",&n);	输入1戓2
	if(n==1) p=max;	如输入1,使p指向max函数
	else if (n==2) p=min;	如输入2,使p指向min函数
	c=(*p)(a,b);		调用p指向的函数
	printf("a=%d,b=%d\n",a,b);
	if(n==1) printf("max=%d\n",c);
	else printf("min=%d\n",c);
	return 0;
}

int max(int x,int y)
{	int z;
	if(x>y) z=x;
	else z=y;
	return(z);
}

int min(int x,int y)
{	int z;
	if(x<y) z=x;
	else z=y;
	return(z);
}

 实在写累了|墙|ョ゚ェ゚;)下周再来补了

自定义函数里的指针本身也是一个本地变量

2019.10.25(补充) 这一段是源自昨晚的一个错误。这是一个通过建立链表来存储学生数据的题目

t#include<stdio.h>
#include<math.h>
#include<stdlib.h>
typedef struct student
{
	int sno;
	char sname[20];
	char sex;
	int age;
	struct student* next;
}stu;
void create(stu* head);
void listfree(stu* head);
int main(int argc,char *argv[])
{
	stu student;
	//student.sno=233;
	create(&student);
	for(stu* p=&(student);p;p=p->next)
	{
		printf("%d\n",p->sno);
	}
	listfree(&student);
	
return 0;
}
这是对的吗???
void create(stu* head)
{
	stu* ptail=NULL;
	int num=0;
	printf("输入学生数据个数");scanf("%d",&num);
	for(int i=0;i<num;i++)
	{
		stu* p=(stu*)malloc(sizeof(stu));
		printf("no:");scanf("%d",&(p->sno));fflush(stdin);
		printf("name:");gets(p->sname); 
		printf("sex:");(p->sex)=getchar();
		printf("age:");scanf("%d",&(p->age));
		p->next=NULL;
		printf("\n");
		if(i==0)
		{
			head=p;
			ptail=p;
		}else
		{
			ptail->next=p;
			ptail=ptail->next; 
		}
	}
} 

void listfree(stu* head)
{
	stu* node=NULL;
	while(head->next)
	{
		node=head->next;
		free(head);
		head=node;		
	}
}

这个与上面有什么不同?它是对的吗?
void create(stu* head)
{
	stu* ptail=NULL;
	int num=0;
	printf("输入学生数据个数");scanf("%d",&num);
	for(int i=0;i<num;i++)
	{
		if(i==0)
		{
			printf("no:");scanf("%d",&(head->sno));fflush(stdin);
			printf("name:");gets(head->sname); 
			printf("sex:");(head->sex)=getchar();
			printf("age:");scanf("%d",&(head->age));
			head->next=NULL;
			printf("\n");			
		    ptail=head;
		}
		else
		{
			stu* p=(stu*)malloc(sizeof(stu));
			printf("no:");scanf("%d",&(p->sno));fflush(stdin);
			printf("name:");gets(p->sname); 
			printf("sex:");(p->sex)=getchar();
			printf("age:");scanf("%d",&(p->age));
			p->next=NULL;
			printf("\n");
			ptail->next=p;
			ptail=ptail->next; 
		}
	}	
} 

 思考了之后,答案揭晓:第一个是错的,第二个是对的。很明显不是链表的创建出错了。实际上链表是完全正确的(如果看到这里的你还不懂链表也没有关系^_^,不过最好去查一查malloc是什么)(因为这里的小标题是指针)那么我用2张图来画出它们的逻辑,看看你是否看懂了这2大串代码

 能看出来了吧?第一个是创建了一个链表,然后把这里链表的头头的指针赋值给了&stu

第二个则是把&stu当做头头,然后把接下来的东西接到&stu后面。

问题就出在红字划线的地方。或许你刚学指针,不知道发生了啥,或是还没有意识到?我将再一次用经典的swap来说明

#include<stdio.h>
void swap(int* x,int* y);
int main(int argc,char *argv[])
{
	int a=3,b=4;
	swap(&a,&b);
	printf("a=%d,b=%d",a,b);这里a和b没有发生交换
return 0;
}

void swap(int* x,int* y)
{                       把指针x和y自身的值做了交换==指向交换  
	int* t;          注意!不是把x指向的东西与y指向的东西交换
	t=x;            重点理解上面2行。这2行字是导致这个错误的关键
	x=y;
	y=t;
}

这里我更愿意用副本(或者叫替身使者更好理解呢?(*^▽^*))的概念来解释:)!

也就是说这些操作都是对替身使者们做的,对本体没有任何影响,所以在自定义函数调用完之后,这些替身使者就被free了

一个关于自定义函数的神秘链接(简单说明了替身使者与本体的关系)可以看看 https://mp.csdn.net/postedit/101392915

所以,这也是我第一个create失败的原因。因为窝是在自定义函数里对替身使者们操作,对本体没有影响。翻到小标题开始,试试看把注释的句子+回去的结果?相信你已经明白发生了啥了。 

多级指针

来了来了,这回开始的是多级指针(这里拿二级指针做例子) 

#include<stdio.h>
void swap(int** a,int** b);
int main()
{
	int a=3,b=4;
	int* pa=&a;
	int* pb=&b;
	swap(&pa,&pb);
	printf("a=%d\nb=%d",a,b);
}

void swap(int** a,int** b)
{
    int temp1=0;
    int* ptemp=&temp1;
	int** temp=&ptemp;
	
	
	*(*temp)=*(*a);
	*(*a)=*(*b);
	*(*b)=*(*temp); 
}

通过这个例子,指针在我的眼里变成了一个木偶师。 

二级指针可以控制一级指针的动作,控制一级指针的动作同时从而影响变量。(这个不准确,可能不好理解。只能意会了)

接下来就是

指针数组 

int* p[int number];与行指针的区别一定要记牢了!int (*p)[int numeber]

指针数组一般用来处理多个字符串(不一定的)int数组里每个room都存一个int,指针数组里每个room都存一个指针。

没错一周过去了我只码了这么一点(*^▽^*)等下一周继续更吧2019.10.20

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值