格式说明符
%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