C语言
3 循环结构
3.1 for循环
for(循环变量赋初值;循环条件;循环变量增量)语句执行顺序
(1)循环变量赋初值1
(2)循环条件
(3)满足条件,执行语句;
(4)循环变量增量
案例1:
#include<stdio.h>
void paymid(int n);
int main(void)
{
paymid(5);
return 0;
}
void paymid(int n)
{
int i,j;
for(i=1;i<=n;i++){
for(j=1;j<=n-i;j++)
printf("#");
for(j=1;j<=2*i-1;j++)
printf("%d",i);
putchar('\n');
}
}
运行结果:
三级目录
3.2 continue 和 break
(1)continue语句是结束本次循环,而不是终止整个循环的执行。
(2)break语句是结束整个循环过程,不再判断循环的条件是否成立。
4 数组
数组:数组是一些具有相同类型的数据的集合,在定义数组之后,系统根据数组中元素的类型及个数在内存中分配了一段连续的存储单元用于存放数组中的各个元素。数组名是一个地址常量,存放数组内存空间的首地址,且不允许修改。
案例
案例一:判断回文
字符串是由有效字符和字符串结束符’\0’组成;由于普通数组中数元素的个数是确定的,一般用下标控制循环;而字符串并没有显示地给出有效字符的个数,只规定在字符串结束符’\0’之前的字符都是字符串的有效字符,一般通过比较数组元素的值是否等于’\0’来决定是否结束循环,即用结束符’\0’来控制循环。
#include<stdio.h>
int main(void)
{
int i,k;
char line[80];
printf("Enter a string:");
k = 0;
while((line[k] = getchar())!='\n')
k++;
line[k]='\0';/*字符串结束符'\0'*/
/*判断字符串是否为回文*/
i = 0;/*i是字符串首字符的下标*/
k = k-1; /*k是字符串尾字符的下标*/
/*i和k两个下标从字符串首尾两端同时向中间移动,逐对判断对应字符是否相等*/
while(i<k)
{
if(line[i]!=line[k])
break;
i++;
k--;
}
if(i>=k)/*判断for循环是否正常结束,若是则说明字符串是回文*/
printf("是回文\n");
else
printf("不是回文\n");/*for循环非正常结束,说明对应字符不等*/
return 0;
}
案例二:统计数字个数
输入一个以回车符为结束标志的字符串(少于80个字符),统计其中数字字符的个数;
在这里插入代码片#include<stdio.h>
int main(void)
{
int count,k=0;
char str[80];
printf("输入字符:");
while((str[k]=getchar())!='\n')
k++;
str[k]='\0';/*将结束符'\0'存入数组*/
/*统计字符串中梳子字符的个数*/
count = 0;
for(k=0;str[k]!='\0';k++)
if(str[k]>='0'&&str[k]<='9')
count++;
printf("%d\n",count);
return 0;
}
案例三:进制转换
输入一个以回车符为结束标志的字符串(少于80个字符),统计其中数字字符的个数;
#include<stdio.h>
int main(void)
{
int i,k;
char newchars[80],oldchars[80];
long number;
printf("请输入一个字符串:\n");
i=0;
while((oldchars[i]=getchar())!='\#')
i++;
oldchars[i]='\0';/*将字符串结束符'\0'存入数组*/
/*滤去非十六进制字符后生成新字符串*/
k=0;
for(i=0;oldchars[i]!='\0';i++)
if(oldchars[i]>='0'&&oldchars[i]<='9' || oldchars[i]>='a'&&oldchars[i]<='f' || oldchars[i]>='A'&&oldchars[i]<='F')
{
newchars[k]=oldchars[i];/*放入新字符串*/
k++;
}
newchars[k]='\0';/*新字符串结束标记*/
/*输出十六进制新字符串*/
printf("十六进制:");
for(i=0;newchars[i]!='\0';i++)
putchar(newchars[i]);
printf("\n");
/*转换为十进制整数*/
number = 0;/*存放十进制数,先清0*/
for(i=0;newchars[i]!='\0';i++){/*逐个转换*//
if(newchars[i]>='0'&&newchars[i]<='9')
number = number*16+newchars[i]-'0';
else if(newchars[i]>='a'&&newchars[i]<='f')
number = number*16+newchars[i]-'a'+10;
else if(newchars[i]>='A'&&newchars[k]<='F')
number = number*16+newchars[i]-'A'+10;
}
printf("十进制:%d\n",number);
}
3 指针
3.1 指针
(1)指针即地址,地址就是指针,地址就是内存单元的编号,指针是编号。 i和p都是变量,只不过i是普通变量,只能存放;p是指针变量,能存放变量的地址。
(2)指针变量是存放地址的变量。指针和指针变量是两个不同的概念。但是要注意,通常我们叙述时会把指针变量简称为指针,实际上它们的含义并不一样。
【int * p】
- 不表示定义了一个名字叫做*p的变量;
- 应该这样理解,p是变量名,p变量的数据类型是int *类型;
- p是变量的名字,int * 表示p变量存放的是int类型变量的地址;
【 p=&i】right
- p保存了i的地址,因此p指向i;
- p不是i,i也不是p,修改p的值不会影响i,修改i的值也不会影响p;
【p=i】error 因为类型不一致,p只能存放int类型变量的地址,不能存放int类型变量的值 。
如果一个指针变量指向了一个普通变量,则指针变量就完全等同于普通变量;
例子:如果p是个指针变量,并且p存放了普通变量i的地址,则p就指向了普通变量i;p就完全等同于i;
或者说:在所有出现p的地方都可以替换成i;在所有出现i的地方都可以替换p;
int * p;//p是变量的名字,int * 表示p变量存放的是int类型变量的地址
int i=3;
p=&i;//right(1)p保存了i的地址,因此p指向i;(2)p不是i,i也不是p,修改p的值不会影响i,修改i的值也不会影响p;
p=i;//error,因为类型不一致,p只能存放int类型变量的地址,不能存放int类型变量的值
p=55;//error,原因同上
j=*p//等价于j=i
如果一个指针变量指向了一个普通变量,则*指针变量就完全等同于普通变量;
例子:如果p是个指针变量,并且p存放了普通变量i的地址,则p就指向了普通变量i;*p就完全等同于i;
或者说:在所有出现*p的地方都可以替换成i;在所有出现i的地方都可以替换*p;
*p就是以p的内容为地址的变量;
3.1 指针的重要性
- 通过指针可以表示一些复杂的数据结构,如链表、树和图;
- 快速的传递数据;
- 是函数返回一个以上的值;
- 能够直接访问硬件;
- 能够方便的处理字符串
- 是理解面向对象语言中引用的基础
总结:指针是C语言的灵魂。
3.1 指针的分类
- 基本类型指针
- 指针和数组
- 指针和函数
- 指针和结构体
- 多级指针
3.1 什么是地址
内存单元的编号
从零开始的非负整数
范围:4G【0–4G-1】
3.1 什么是指针
指针就是地址,地址就是指针;指针的本质就是一个操作受限的非负整数。地址(指针)可以进行相减,不能进行相加、相乘、相除。
指针变量就是存放内存单元编号的变量,或者说指针变量就是存放地址的变量。
3.1 动态内存分配
传统数组的缺点
1.数组长度必须事先制定,且只能是常整数,不能是变量;
2.传统数组,该数组的内存无法手动释放,在函数运行期间,系统为该函数分配的空间会一直存在,直到该函数运行完毕时,数组的空间才会被系统释放。
3.数组的长度一旦定义,就不能更改,数组的长度不能在函数运行期间动态地扩充或缩小;
4.A函数定义的数组,在A函数运行期间可以被其它函数使用,但A函数运行完毕之后,A函数中的数组将无法再被其它函数使用。 传统方式定义的数组不能跨函数使用
为什么要动态分配内存
1.动态数组很好地解决了传统数组的这4个缺陷;
2.传统数组也叫静态数组。
1.动态数组很好地解决了传统数组的这4个缺陷;
2.传统数组也叫静态数组。
动态分配内存
静态一维数组
int a[5];//如果int占4个字节的话,则本数组总共包含有20个字节,每4个字节被当作了一个int变量来使用;静态一维数组;
int len;
int *pArr;
int i;
动态构造一维数组
printf(“请输入要存放的元素个数:”);
scanf(“%d”,&len);
pArr=(int *)malloc(4*len);//动态构造一维数组;类似于 int pArr[len];
对一维数组进行操作,如:对一维数组进行赋值
for(i=0;i<len;i++)
scanf(“%d”,&pArr[i]);
对一维数组进行输出;
printf(“”一维数组的内容是:”);
for(i=0;i<len;i++)
printf(“%d”,pArr[i]);
free(pArr);//释放掉动态分配的数组
动态内存和静态内存的比较
静态内存是由系统自动分配,由系统自动释放;
静态内存是在栈分配的;
动态内存是由程序员手动分配,手动释放;
动态内存是在堆分配的;
多级指针
int i=10;
int *p=&i;
int **q=&p;
int ***r=&q;
error 因为r是int ***类型,r只能存放int **类型变量的地址;
r=&p;
p是int *类型,&p是int**类型;
f(&p);
q是个指针变量,无论q是什么类型的指针变量,都只占4个字节;
void f(int **q)
{
int i=5;
*q=&i;
}
动态内存可以跨函数使用
int *p;
f(&p);
printf(“%d\n”,*p);
*q = (int *)malloc(sizedf(int));
seizedf(数据类型) 返回值是该数据类型所占的字节数
void f(int **q)
{
*q = (int *)malloc(sizedf(int));//seized(数据类型) 返回值是该数据类型所 占的字节数;
q=5;//errror;
*q=5;//p=5;errror;
**q=5;//*p=5
}
结构
结构的概念及定义
结构是C语言中一种新的构造数据类型,它能够把有内在联系的不同类型的数据汇聚成一个整体,使它们相互关联;同时,结构又是一个变量的集合,可以按照对基本数据类型的操作方法单独使用其成员变量。(结构类型是由用户根据需求,按规定的格式自行定义的数据类型。)
-
关键字struct和它后面的结构名一起组成了一个新的数据类型名;
-
大括号中定义的成员信息被聚合为一个整体并形成了一个新的数据类型;
-
大括号的内容叫做结构成员,也叫结构分量;
结构变量
定义了结构类型后,还要定义结构类型的变量,然后才能通过结构变量来操作和访问结构的数据。C语言编译器只有在定义了相应的结构变量后才会为其分配存储单元。
- 结构变量的引用:结构成员运算符的优先级属于最高级别,所以一般情况下都是优先执行;
- 相同结构类型的变量之间可以直接赋值;
- 结构变量作为函数参数可以传递多个数据且参数形式较简单。
结构数组
结构数组是结构于数组的结合体,与普通数组的不同之处在于每个数组元素都是一个结构类型的数据,包含多个成员项。 struct student
students[50]={{101,”张三”,76,90},102,”李四”,96,92}}
结构指针
指针可以指向任何一种类型的变量;结构指针就是指向结构变量的指针。
struct student student1={101,”张三”,76,90},* p;
p=&studen1;//p指向结构变量student1;
p=&studen1;//p指向结构变量student1;
使用*p访问结构成员
(*p).num=101;//*p表示p指向的结构变量student1
注意(*p)中的括号是不可少的,因为成员运算符“.”优先于“*”;
使用指向运算符→访问指针指向的结构成员。
student1.num=101;//通过结构变量student1直接访问结构成员;
(*p).num=101;//使用*p访问结构成员
p→num=101;//使用指向运算符→访问指针指向的结构成员。
结构指针作为函数参数
当结构成员数量众多时,在参数传递过程中就需要消耗很多空间,而使用结构指针作为函数参数只要传递一个地址值,可以极大地提高参数传递的效率。
3 游戏案例
3.1 贪吃蛇
#include<time.h>//随机种子来出现食物
#include<coino.h>//监听键盘输入
#include<window.h> //为了使用gotoxy(光标移动函数)
void gotoxy(int x,int y){//系统辅助函数
COORD pos={x,y};
HANDLE hOut=GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(hOut,pos);
}
3.1 2048小游戏
#include<stdio.h>
#include<stdib.h>
#include<time.h>
#include<memory.h>
int panel[4][4];
int score=0;
//方向
enum Direction{
LIFE=1, //A
UP, //W
RIGHT, //D
DOWN //S
}
//初始化数据
void init()
{
srand(time(NULL));
memset(panel,0,sizeof(panel));//初始化0
}
//生成新的数据块
int spawnNewBlock()
{
int haveBlank=0;//定义一个标志,判断是否有空位
//循环遍历数组,看看数组里有没有空位
}
int main(void){
return 0;
}