C语言初阶,知识点简介(2)

2.12 #define定义宏和符号常量

(1)#define 定义符号常量(为了和变量区分,使用大写)


#define MAX 100
int main()
{
	int arr[MAX] = { 0 };  //定义的是常量,可以放在数组的下标中
}

(2)#define 定义宏

#define ADD(X,Y) ((X)+(Y)) 
//编程习惯,为了防止出错,把x和y分别加上括号,例如X是表达式
// ADD和(X,Y)之间没有空格 
int main()
{
	
	int sum = ADD(3, 4);
	
	printf("%d\n", sum);
}


//错误示例
#define ADD(X,Y) (X*Y)    //编程习惯,为了防止出错,把x和y分别加上括号 ADD和(X,Y)之间没有空格 

int main()
{
	int multiply = ADD(3+5, 4);  //输出的是23,实际应该是32

	printf("%d\n", sum);
}

2.13内存的划分

从操作系统的角度对内存进行划分,可以分为

栈区:局部变量

堆区:动态分配内存

静态区:全局变量,静态变量

类似将国土面积,划分为一个个省市等,找到房间,需要找到房间的编号,即地址。把内存划分为一个个小的内存单元,访问内存单元需要提供地址,每个内存单元的编号就是内存单元的地址。计算机中的内存划分是以字节为单位的,即1Byte=8bit,每一个地址都对应一个内存单元,8个比特对应一个地址。

根据地址线的数量,计算机分为32位和64位。以32位操作系统为例,(包含32根物理的电线)计算机通电之后,电信号转为数字信号(正电1负电0),

数据类型(int ,char float)每次申请空间以字节为单位,所以1个内存单元代表1个字节,内存划分为一个个小的内存单元,一个内存单元的大小是一个字节,为了使用内存单元,对其进行编号,编号是通过地址线产生的二进制序列。

2.14指针

        指针是用来存放地址的变量。在定义指针类型的时候,前面的*代表所定义的变量是一个指针,int 代表所指向的变量是一个整型变量

int main()
{
	int a = 100;
	int* p = &a; //取地址操作符
	//*p代表p是指针,前面的int代表p指向的是一个整型变量 a
	//
}

        在定义时候使用*p代表的是指针,代表所指向变量的地址,在使用时候*p代表对地址的解引用,即得到所指向的变量。

int main()
{
    int a=100;
    int *p=&a; //定义指针,指向的是a的地址
    *p=20; //解引用指针,修改的是a的值
    printf("%d\n",a);

    return 0;
}

        

每个内存单元都有一个编号,就是地址。指针变量的大小由地址决定的,32位需要32个bit位存放,即4个字节,而与指向变量的类型无关。

int main()
{
	int a = 10;
	int* pa = &a;   //定义了一个指向a的指针pa
                   //*pa 得到a的值 

	char c = 'a';
	char* pc = &c;

	float f = 2.13;
	float* pf = &f;

	double d = 3.22;
	double* pd = &d;

	printf("%d ", sizeof(pa));//4
	printf("%d ", sizeof(pc));//4
	printf("%d ", sizeof(pf));//4
	printf("%d ", sizeof(pd));//4
}

2.15结构体

        C语言提供了一些内置的简单数据类型,但是并不能满足构造复杂对象的需求,例如人是复杂的对象(年龄,身高,身份证,性别等),不能用一个或者一种简单的数据类型进行表达。需要创建一个复杂类型结构体类型,使得C语言有能力描述复杂类型。

struct Stu
{
	char name[20];
	int age;
	char sex[5];
	char id[15];
	
}; // 一般的编辑器会提供,注意末尾的分号一定不能省


int main()
{
	//汉字占两个字符,所以不可以使用''
	//创建并初始化结构体对象
	struct Stu s1 = { "张三",30,"男","340604" };
	//结构体对象使用.进行引用
	printf("name = %s age = %d sex=%s id = %s\n ", s1.name, s1.age, s1.sex, s1.id);

	//创建结构体指针,使用->访问结构体成员
	struct	Stu* ps = &s1;
	printf("name = %s age = %d sex=%s id = %s\n ", ps->name, ps->age, ps->sex, ps->id);
	printf("name = %s age = %d sex=%s id = %s\n ", (*ps).name,(*ps).age,(*ps).sex,(*ps).id);
}

2.16循环和分支

C语言中由一个分号;隔开的就是一条语句。

例如:1+2;

        printf("hello world");

分支语句(选择结构)

(1) if (表达式)

        语句;

(2) if (表达式)

                语句1;

      else

                语句2;

(3)多分支

        if(表达式1)

                 语句1;

        else if(表达式2)

                  语句2;

        else

                   语句3;

注意:《1》if后面的表达式没有分号,表达式结果为真(非0)则执行后面的语句

           《2》只能跟着一条语句,多条语句使用复合结构

int main()
{
 int score=10;
 scanf("%d",&score);
 if(score>60)    //输入的语句多于一条,使用复合语句
 {
     printf("输入的成绩大于60\n");
     printf("考试成绩合格\n");
}

    《3》else语句和最近的if配对,而不是和形式上对齐的if配对

int main()
{
 int score=0;
 scanf("%d",&score);

 if(score>60)   
     if(score>90)
     printf("输入的分数大于90,成绩良好\n");
 else                    //else语句和第二个if配对而不是和形式上对齐的第一个if配对
     printf("需要补考\n");   

}

书写建议是多使用{}把逻辑的关系理清

int main()
{
 int score=0;
 scanf("%d",&score);

 if(score>60)   
    {
     if(score>90)
     printf("输入的分数大于90,成绩良好\n");
    }
 else                    //使用{}之后 ,第二个if语句成了第一个if语句的一部分,else和第一个if配对
     printf("需要补考\n");   

}

《4》if后面的表达式包含多个判断条件时,例如

int main()
{
 int score=0;
 scanf("%d",&score);

 if(90<score<100)   //此种方式错误,进行关系判断的时候,得到的值为0或者1
    //假设输入的是91,则91>90得到的结果是1,再和100进行判断,即1<100结果为真
     //假设输入的是10,则10>90得到的结果是0,再和100进行判断,即0<100结果为真
       //所以需要使用逻辑运算符&& 
//代码修改为if(score>90&&score<100)
    printf("成绩优异\n"); 
   

}

《5》if if else 和if else if  else的区别

在if if else语句的结构中,if都会被执行,如果下面这个程序输入的是99,则会输出两次

int main()
{
	int score = 0;
	scanf("%d", &score);
	
	if (score > 90)
		printf("恭喜您,考试成绩为%d\n",score);
	if(score>80)
		printf("还不错,考试成绩为%d\n",score);
	else
		printf("加把油,考试成绩为%d",score);

}

在if else if语句的结构中,只有一个if会被执行,如果下面这个程序输入的是99,则会输出1

int main()
{
	int score = 0;
	scanf("%d", &score);
	
	if (score > 90)
		printf("恭喜您,考试成绩为%d\n",score);
	else if(score>80)
		printf("还不错,考试成绩为%d\n",score);
	else
		printf("加把油,考试成绩为%d",score);

}

return作为语句的结束标志,可以直接返回,即结束函数

2.17 switch语句

switch是一种分支语句,常用于处理多个分支的情况。例如输入每个星期对应的日期,如果使用if else语句,显得过于繁琐。

int main()
{
	int day = 0;
	scanf("%d", &day);
	
	if (1==day)
		printf("星期1\n");
	else if(2==day)
		printf("星期2\n");
    else if(3==day)
		printf("星期3\n");
    else if(4==day)
		printf("星期4\n");
    else if(5==day)
		printf("星期5\n");
    else if(6==day)
		printf("星期6\n");
	else
		printf("星期天\n");

}

使用switch语句进行判断,

int main()
{
	int day = 0;
	scanf("%d", &day);
	
	switch(day)
    {
    case 1:
		printf("星期1\n");
        break;
	case 2:
		printf("星期2\n");
        break;
    case 3:
		printf("星期3\n");
        break;
    case 4:
		printf("星期4\n");
        break;
    case 5:
		printf("星期5\n");
        break;
    case 6:
		printf("星期6\n");
        break;
    case 7:
		printf("星期7\n");
        break;
    }

}

注意:《1》switch(整型表达式)建议定义为int ,short有时候会出现溢出的错误

           《2》case语句是分支,不是循环,不可以使用continue

           《3》使用break跳出当前的循环,如果没有break,case语句会顺序接着执行

           《4》switch中的语句是可以任意调换的

int main()
{
	int day = 0;
	scanf("%d", &day);
	
	switch(day)
    {
    case 1:
	case 2:
    case 3:
    case 4:
    case 5:
		printf("工作日\n");
        break;
    case 6:
    case 7:
		printf("休息日\n");
        break;
    }

}

只能在循环中使用continue,跳出此次循环的后面部分,进行下一次的循环,跳转到while语句的判断部分


//1 2 3 4 死循环
int main()
{
	int i = 1;
	while(i<=10)
    {
      if(i==5)
       {
            continue;
       }
    printf("%d ",i);
    i++;

    }
    
}

如果是break,则跳出当前的循环


//1 2 3 4 
int main()
{
	int i = 1;
	while(i<=10)
    {
      if(i==5)
       {
            break;
       }
    printf("%d ",i);
    i++;

    }
    
}

在windows系统安装的vs2019使用ctrl+z作为EOF(文件结束标识符),getchar是从输入缓冲区中获取的一个字符,其函数原型是

int getchar( void ); 函数返回的是一个int型,因为字符在计算机中以整数的形式存储

int main()
{
    int ch = 0;
    while ((ch = getchar()) != EOF)
        putchar(ch);
    return 0;
}

scanf函数触发中断,程序等待用户输入,在输入\n后把缓冲区中的数据取出放到对应的地址中,getchar在输入缓冲区中读取到输入时候的\n,所以程序直接跳过。

int main()
{
	int ch = 0;
	char password[20] = { 0 };

	printf("请输入密码>:");
	scanf("%s", password);

	printf("请输入(Y/N);>");
	ch = getchar();

	if ('Y' == ch)
	{
		printf("确认成功\n");
	}
	else
	{
		printf("放弃确认\n");
	}
}

修改方案一:此时可以获取一个\n,但是当scanf输入的数字类似 12 3 4 ,程序依然出错

int main()
{
	int ch = 0;
	char password[20] = { 0 };

	printf("请输入密码>:");
	scanf("%s", password);

	ch = getchar();//获取输入的\n

	printf("请输入(Y/N);>");
	ch = getchar();

	if ('Y' == ch)
	{
		printf("确认成功\n");
	}
	else
	{
		printf("放弃确认\n");
	}
}

修改方案二:使用scanf进行输入的时候以空白(空格,TAB,换行)作为输入结束的标识符

 \n表示的时输入结束,真正被scanf读取的是第一个空白之前的数据

int main()
{
	int ch = 0;
	char password[20] = { 0 };

	printf("请输入密码>:");
	scanf("%s", password);

	while ((ch = getchar()) !='\n')   //使用scanf输入时,\n表示输入结束,所以当不是\n时
 //把输入的字符使用getchar()存储,表示的时输入结束,真正被scanf读取的是第一个空白之前的数据
	{

	}

	printf("请输入(Y/N);>");
	ch = getchar();

	if ('Y' == ch)
	{
		printf("确认成功\n");
	}
	else
	{
		printf("放弃确认\n");
	}
}

2.18循环语句

while语句

int main()
{

    int i=0;  //初始化部分

    while(i<10)        //判断部分
    {

    printf("%d ",i);
    i+=2;    //调整部分

    }


}

由于while语句三个部分不集中,为了解决这个问题引入for循环,

int main()
{

   for(i=0;i<10;i++)  //初始化;条件判断部分;调整部分;
    {
        if(i==5)
            continue;

        printf("%d ",i);
    }

}

int main()
{

   for(i=0;i<10;i++)  //初始化;条件判断部分;调整部分;
    {
        if(i==5)
            break;

        printf("%d ",i);
    }

}

不要随意省略表达式,否则会出现各种未知错误,出了错误学会自己调节

int main()
{
	int i = 0;
	int j = 0;
	int count = 1;
	for (i = 0; i < 10; i++)
	{
		for (j = 0; j < 10; j++)
		{
			printf("%d\n", count);
			count++;//循环100次
		}
	}
}

但是下面的代码仅仅执行20次,因为在第一次执行完j的循环之后,j=10,再次进行i=1的判断时,j的循环变量不满足条件,所以并不进入,但是此时i仍然需要增加。

int main()
{
	int i = 0;
	int j = 0;
	int count = 1;
    int count1= 1; 
	for (; i < 10; i++)
	{
        printf("%d\n", count1);
		for (; j < 10; j++)
		{
			printf("%d\n", count);
			count++;//循环10次
		}
	}
}

 如果判断条件为假,则一次也不执行。

int main()
{
	int i = 0;
	int k = 0;
	for (i=0,k=0; k=0; i++,k++)
	{
	    k++;
	}
}

任何表达式都是有值的,b=(a=3) 赋值符号是右结合性,a的值等于3。

int main()
{
	int i = 0;
	do
    {    
        if(i==5)
            continue;
        
        printf("%d ",i);
        i++;
    }while(i<=10);
    return 0;
}

全局变量:在所有函数之前定义的变量

局部变量:在函数内或者复合语句内部定义的变量

int main()
{
	int i = 0;                     //局部变量
	int j = 0;
	int count = 1;
    int count1= 1; 
	for (; i < 10; i++)
	{
        printf("%d\n", count1);
		for (; j < 10; j++)
		{
			printf("%d\n", count);
			count++;//循环10次
		}
	}
}

局部变量实在执行该函数或复合语句时自动建立的,当该函数或者复合语句执行完毕后自动释放,所以在不同的函数或者复合语句中定义同名的局部变量,也不会相互干扰。

写代码都是进行累计的,不会写循环,先写一次,在考虑循环的环境

例子:查找数字

int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,0 };
	int n = 7;
	int i = 0;

	for (i = 0; i < 10; i++)
	{
		if (arr[i] == n)
		{
			printf("找到了:%d\n", i);
			break;
		}
	}
	if (i == 10)
	{
		printf("找不到\n");
	}
	return 0;
}

使用srand我们规定只定义一次就可以,参数是unsigned int 类型

但是time返回的是time_t类型,所以需要类型转换

void game()
{
	int guess = 0;
	int ret = rand() % 100 + 1;

	while (1)
	{
		printf("请输入猜测的数字:>");
		scanf("%d", &guess);
		if (guess > ret)
		{
			printf("猜大了\n");
		}
		else if (guess < ret)
		{
			printf("猜小了\n");
		}
		else
		{
			printf("恭喜你,猜对了\n");
			break;
		}
	}

}
void menu()
{
	printf("*******************\n");
	printf("*****  0.exit *****\n");
	printf("*****  1.play******\n");
	printf("*******************\n");
}
int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do {
		menu();
		scanf("%d", &input);
	switch (input) 
	{
	case 0:
		printf("游戏结束\n");
		break;
	case 1:
		game();
		break;
	default:
		printf("输入错误\n");
		break;
	}
	   } while (input);

}

system("shutdown -s -t 60"); 关机

system("shutdown -a");取消关机    等价于在cmd中输入

if else if 和if if的区别,如果一个进去了,if else if就不在进去,对于if 和if来说,一个进去了,另一个还需要再次进入判断

函数

使用函数,

1.提高了开发的效率

2.提供统一的标准。

函数分为两种,库函数和自定义函数。

库函数:把一些常用的功能用C语言封装成了函数,放在C语言的库函数中

#include<stdio.h>
#include<math.h>

int main()
{

char arr1[]="hello bit";
char arr2[20]={0};

strcpy(arr2,arr1);
printf("%s\n",arr2);

}
#include<stdio.h>
#include<math.h>

int main()
{

char arr1[]="hello bit";

memset(arr,'*',5);

printf("%s\n",arr);

}

函数内部想要改变函数外部的值,使用指针传递。

void Swap(int a,int b)  //当实参传给形参的时候,形参是实参的临时拷贝
{

    int tmp=a;
    a=b;
    b=tmp;

}
void Swap1(int *a,int *b)//当实参传给形参的时候,形参是实参的临时拷贝
{

    int tmp=a;
    a=b;
    b=tmp;

}



int main()
{
	int x=0,y=0;
    scanf("%d%d",&x,&y);
    printf("交换前:x=%d y=%d\n",x,y);

    Swap(x,y);
    Swap1(&x,&y);

	return 0;
}

自定义函数:根据用户需求定义的函数。和库函数一样,有函数名,返回值类型和函数参数。

函数的组成:

ret_type fun_name(para1,*)   返回类型  函数名  函数参数

{

statement;

}

函数参数(实参):

真实传递给函数的参数,即实参,实参可以是常量,变量,表达式,函数等。无论实参是何种类型的量,在进行函数调用时,它们都必须要有确定的值,以便把这些值传递给形参。

int a=10;
int max=get_max(1,2);
max=get_max(1,a);
max=get_max(1+4,get_max(2,3));

形式参数(形参):

形式参数是指函数名后括号中的变量,因为形式参数只有在函数被调用的过程中实例化,调用完成后自动销毁,只在函数中有效。

形参可以是变量,表达式和函数调用

int a=10;
int max=get_max(1,a); //变量    
max = get_max(1+4,get_max(2,3)); //表达式,函数

不需要返回值的时候,前面一定要加上void,有些编辑器返回的默认值是int

一般不在函数内部进行打印,因为这样就相当于在一个函数内部生成了两个功能。例如程序员A仅需要得到max的值,所以函数功能不完善,建议一个函数仅仅实现一个功能。代码的复用性高。让函数的功能更加独立。

       

void get_max(int a,int b)
{
    int max=(a>b)?(a):(b);
    printf("%d\n",max); //实现了打印的功能
}

int get_max(int a,int b)
{
    int max=(a>b)?(a):(b);
    return max;    //为了保证函数代码的独立性
}

int main()
{

    int a=0;
    int b=0;
    scanf("%d%d",&a,&b);
    int m=get_max(a,b);
    
    printf("%d\n",m);//实现了打印的功能
}

最害怕的是没开始就放弃,第一篇博客的约定是什么?

void new_line()
{
	printf("hehe\n");
}

void three_line()
{
	int i = 0;
	for (i = 0;i < 3; i++)
	{
		new_line();// 函数可以嵌套使用
	}
	printf("hehe\n");
}





void Add(int *p)
{
 void test()    //函数不可以嵌套定义
  {


   }
    *p=*p+1;

}

链式访问

把一个函数的返回值作为另外一个函数的参数

int main()
{
  
    int len=strlen("abcdef");
    printf("%d\n",len);


    //链式访问
    printf("%d\n",strlen("abcdef"));


    // 4321 print返回打印的字符的个数
    printf("%d",printf("%d",printf("%d",43)));
    // 4322 换行也是一个字符
    printf("%d",printf("%d\n",printf("%d",43)));
}

程序从main函数开始执行,


int Add(int x,int y)
{
 int z=x+y;
 return z;
}

int main()
{
  
    int a=10;
    int b=20;
    int ret=Add(a,b);
    printf("%d\n",ret);
}

如果想把Add函数写在主函数的后面,则需要在main之前进行函数声明,即

int Add(int x,int y);
int main()
{
  
    int a=10;
    int b=20;
    int ret=Add(a,b);
    printf("%d\n",ret);
}
int Add(int x,int y)
{
 int z=x+y;
 return z;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值