-
C第七天
今天讲的主要是函数指针和字符串,到了这儿已经做不出老师出的题目了,通常都是知道大概的思路但是无法用代码表达出来。老师针对我们近阶段的学习,给我们留了一道几乎能用到之前所有知识点的作业——商人过河,思路很清晰,就是不知道怎么用代码表达。
1.指向一个基本类型变量(int)的指针
int *p;
2.指向一个int型数组的指针,int a[5];
int (*p)[5]
3.定义一个函数的指针。
void func();
int func(int a,int b)
函数的指针——函数指针。
void (*p)()=func;//定义一个指向函数返回值为void,并且函数不带参数的函数的指针变量,并给这个指针变量赋了值,让它指向此类型函数中的func函数。
void (*p)()=&func;也是可以
int (*p)(int,int)=func;//定义了一个指向函数返回值为int,并且函数带有2个int型参数的函数的指针变量,并给整个变量赋了值,让它指向此类型函数中的func函数。
例:
#include <stdio.h>
void func1()
{
printf("func1 be called!\n");
}
int func2(int a)
{
printf("func2 be called! a=%d\n",a);
return 0;
}
void main()
{
void (*pfun1)();
pfun1=func1;//让pfun1指向func1函数
//pfun1=&func1;//也可以这样写
//(*pfun1)();
int (*pfun2)(int);
pfun2=func2;//让pfunc2指向func2函数
pfun1();//通过指针调用func1函数
pfun2(10);//通过指针调用func2函数
}
#include <stdio.h>
/*
void func(int num1,int num2)
{
++num1;
++num2;
printf("num1=%d num2=%d\n",num1,num2);
}
void main()
{
int num1=1,num2=2;
func(num1,num2);//int num1=num1
printf("num1=%d num2=%d\n",num1,num2);
}
*/
/*错误写法
void func()
{
int num=5;
}
void main()
{
func();
printf("num=%d\n",num);
}*/
void main()
{
int num;
printf("%d\n",num);
}
/*
局部变量:定义在函数内的变量。
1.各个函数里面的变量可以同名,并且相互不影响,因为局部变量的作用域只限于定义它的函数体内。
2.它的生命周期始于定义它的那一刻,终于定义它的函数的结束之前.在定义的时候会给他分配空间,结束的时候空间会被释放。
3.局部变量如果没有赋值,将是随机值。
*/
#include <stdio.h>
int num=1;
void func1()
{
int num=3;
printf("num=%d\n",num);
}
void func2()
{
printf("num=%d\n",num);
}
void main()
{
int num=2;
printf("num=%d\n",num);
func1(); func2();
printf("num=%d\n",num);
}
/*
全局变量:定义在函数外面的变量。
特点:1.不赋值,默认为0
2.如果全局变量和局部变量同名,起作用的是局部变量。
3.在函数中如果没有同名的局部变量,那么起作用的是全局变量
*/
#include <stdio.h>
/*
void func()
{
int i;
for(i=1;i<=3;i++)
{
static int a=1;
a++;
printf("a:%d\n",a);
}
}
void main()
{
func();
// printf("a:%d\n",a);
}
*/
/*
void main()
{
static int a;
printf("a=%d\n",a);
}
*/
static int a;
void main()
{
printf("a:%d\n",a);
}
/*
static:静态的
静态变量:用static修饰的变量。
静态局部变量:用static修饰的局部变量
特点:1.作用域只限于定义它的函数体内。
2.它分配的空间会一直存在,即使当定义它的函数结束了,它里面的值也能保留下来,只是出了函数就不能再用了,因为它的作用域只限于定义他的函数。直到整个程序结束,空间被释放。
3.静态局部变量没有赋初值,则默认为0.
静态全局变量:static修饰的全局变量
特点:
1.没有赋值的话,为0
2.只能在定义它的文件中用,在其他文件中不能用
全局变量的特点:
1.没有赋值的话,默认为0
2.作用于整个程序,除了定义它的文件可以使用它,其他文件中也能使用它,但是在其他文件中使用它之前先声明它,声明语句:如:int a;
*/
#include <stdio.h>
void main()
{
const int a=1;
printf("a:%d\n",a);
// a=2;
// printf("a:%d\n",a);
}
//常变量:用const修饰的变量,虽然是变量,但体现着常量的特性,只能访问它的值,不能修改它的值,它的值只能在定义这个变量的时候以初始化的方式被赋值。
练习:给出年,月,日,判断该天是一年中的第几天?
方法1
#include <stdio.h>
int a[]={31,28,31,30,31,30,31,31,30,31,30};
int Isleap(int);
int Sum(int,int);
void main()
{
int year,month,day;
printf("输入年、月、日:");
scanf("%d %d %d",&year,&month,&day);
int days=Sum(month,day);
if(Isleap(year) && month>2)
days=days+1;
printf("总天数:%d\n",days);
}
int Sum(int month,int day)
{
int i;
for(i=1;i<month;i++)
day=day+a[i-1];
return day;
}
int Isleap(int year)
{
return (year%4==0 && year%100!=0)||(year%400==0);
}
方法2
#include <stdio.h>
int Isleap(int);
void main()
{
int year,month,day;
printf("请输入年、月、日:");
scanf("%d %d %d",&year,&month,&day);
switch(month-1)
{
case 11:
day += 30;
case 10:
day += 31;
case 9:
day += 30;
case 8:
day += 31;
case 7:
day += 31;
case 6:
day += 30;
case 5:
day += 31;
case 4:
day += 30;
case 3:
day += 31;
case 2:
day += Isleap(year)+28;
case 1:
day += 31;
}
printf("总天数:%d\n",day);
}
int Isleap(int year)
{
return (year%4==0 && year%100!=0)||(year%400==0);
}
homework:
游戏说明:
有3个商人带着3随从和货物过河,船每次最多只能载2个人,由他们自己划行,并且如何乘船渡河的大权由商人们掌握。要求保证在过河期间的任一岸上商人的人数大于或者等于随从的人数,否则随从会杀死商人抢夺货物。设计一个符合上述要求的商人过河游戏。
游戏规则:
1.依次输入过河的商人和随从人数
2.非法输入按键将重新开始游戏(例如:输入的人数不能超过2,所以负数,字符属于非法输入)
程序设计要点:
1.界面友好,光标定位,字体或者背景颜色控制
2.多些功能子函数,主函数的功能只是负责调用子函数。
解题思路:
设商人为A,B,C。随从为a,b,c 渡河过程:
1.A 带a渡河
2.A将船划回来
3.b.c两名随从接着划船渡河
4.c将船划回来
5.A B两名商人划船渡河
6.B b主仆二人划船回来
7.B C两人划船渡河
8.a划船回来
9.a b 渡河
10.商人C划船回来
11.商人C带c划船渡河
字符串常量:用双引号括起来的任意字符序列。 “asdfg”.
因为在c语言中没有专门字符串类型,所以无法定义一个字符串变量用来接受一个字符串常量。所以通常定义一个字符数组,用来存储字符串常量。
例:
char a[]="sdfghjk"; sizeof(a)<=>8
char a[]={'s','d','f','g'}; sizeof(a)<=>4
特点:
1.字符串常量默认以'\0'字符结尾。
sizeof(变量名/类型);
sizeof(a):计算出以整个地址为起始地址的一段连续内存的长度。
2.一个字符串常量,本身就表示一个指针,即一个地址,该字符串首元素的地址,作为一个指针指向的对象是该字符串中的字符。
例:
#include <stdio.h>
void main()
{
char *p="asdfgh";
printf("*p=%c *(p+1)=%c\n",*p,*(p+1));
printf("%d\n",sizeof(p));
}
//系统中32位指针长度是4;64位指针长度为8
gets(地址):从标准输入(键盘)获取一行字符串,在获取字符串时,会把获取的最后一个字符‘\n’,换成'\0'存储。
例:
#include <stdio.h>
void main()
{
char name[30];
gets(name);
printf("%s\n",name);
}
练习:从键盘获取一行字符串,统计含有多少个空格
#include <stdio.h>
void main()
{
char name[30];
gets(name);
/*
int i=0,count=0;
while(name[i]!='\0')
{
if(name[i]==' ')
count++;
i++;
}
*/
char *p=name;
int count=0;
while(*p!='\0')
{
if(*p==' ')
count++;
p++;
}
printf("%d\n",count);
}
homework:利用递归函数,逆序输出一个字符串。这是昨天的作业,直到讲到这儿才拿出来讲,因为需要用到今天学到的内容
#include <stdio.h>
void Inverse(char *str)
{
if(*str=='\0')
return;
Inverse(str+1);
printf("%c",*str);
}
void main()
{
char *str="abcdefgh";
Inverse(str);
printf("\n");
}
puts(地址):向屏幕输出字符串,括号里面的地址可以是数组名/字符串常量/指针变量。输出字符串会自动换行
#include <stdio.h>
void main()
{
char name[30]="asdfghj";
char *p="aaaaaaa";
puts("bbbbbbbb");
puts(name);
puts(p);
}
练习:自己写个函数mygets(),实现gets的功能,但不会出现越界。
#include <stdio.h>
void mygets(char *a,int len)
{
int i;
for(i=0;i<len-1;i++)
{
a[i]=getchar();
if(a[i]=='\n')
break;
}
if(a[i]!='\n')
{
while(getchar()!='\n');//吸收多余的字符。
}
a[i]='\0';
}
void main()
{
char a[30];
mygets(a,30);
printf("%s\n",a);
}
strlen():计算字符串的字符个数,并把计算结果返回出来,用整个函数要包含头文件:string.h
例:
#include <stdio.h>
#include <string.h>
void main()
{
char a[]="i love beijing";
int len1,len2;
len1=strlen(a);
len2=strlen("i love beijing");
printf("%d %d\n",len1,len2);
}
练习:自己写个函数mystrlen()实现strlen的功能。
#include <stdio.h>
#include <string.h>
int mystrlen(char *str)
{
int c=0;
while(*str!='\0')
{
str++;
c++;
}
return c;
}
void main()
{
char *str="asdfghjk";
int n=mystrlen(str);
printf("%d\n",n);
}