C语言学习笔记(入门篇二)(从零到函数)

214 阅读10分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第10天,点击查看活动详情

Preface

以前的博文~

C语言简介

c语言是一门面向过程、抽象化的通用程序设计语言,广泛应用于底层开发。C语言具有高效、灵活、功能丰富、表达力强和较高的可移植性等特点,在程序设计中备受青睐。C语言编译器普遍存在于各种不同的操作系统中,例如Microsoft Windows、macOS、Linux、Unix等。C语言的设计影响了众多后来的编程语言,例如C++、Objective-C、Java、C#等。

C语言语法结构

先看一段最简单的面世程序:

#include<stdio.h> 
int main()//int 表示函数的返回值的类型,main为函数名
{
    printf("Hello World");//printf()为输出函数,可以等价于fprintf(stdout,"Hello world")
/*每一条C语言语句结束后必须加上;号.*/
    return 0; //函数返回值
}

这段代码中包含了一个最基本的程序结构 其中#include<stdio.h>是引入一个头文件,这个头文件包含了某些c语言编写的函数的声明,换一句话说就是使用别人写好的函数所做的声明.类等价于python中的import 库名 这里还需要注意的是在不同的C语言版本中的某些语法是有些差异的.比如在vc2010中代码还可以写为

#include<stdio.h>
void main(){

	printf("Hello world");

}

除此以外C语言中运行时只会执行main函数的内容,只有当在main函数内调用到其他函数时才会跳到其他函数中运行相关代码

C语言格式化输入与输出

(首先说明一下很重要的一点,在C语言中所有的硬件比如键盘,鼠标对于C语言而言都作为文件对象.这一点在后面的文件操作中尤为重要.) 一.输出函数 printf("Hello world")这里就输出了一个字符串. 接下来使用一个案例具体说明;

#include<stdio.h>
void main(){
	int a=3;
	float b=3.0f;
	double c=3.0;
	char *str="Hello"//通过字符串指针指向一个字符串,这里你只需要知道,str是一个字符串即可
	char d='a';
	printf("a=%d,b=%f,c=%f,str=%s,d=%c",a,b,c,str,d);
}

二.输入函数scanf() 这个函数的核心就是格式二字,下面是一段示例;

#include<stdio.h>
void main(){
	char a;//创建一个字符变量a
	char str[100];//创建一个字符数组存放字符串
	scanf("a=%c,str=%s",&a,str);
	/*scanf()函数将值写入变量对应的内存中,所以要用取地址符号比如&a,
	但是对以一个数组则本身就是以地址的形式传递的因此不需要加*/
	printf("a=%c,str=%s",a,str);
	
}

接下来就是重点,程序的输入必须要以 a=a,b=hello输入. 在这里插入图片描述

原因就是

scanf("a=%c,str=%s",&a,str); 如果改一下 scanf("%c,%s",&a,str); 此时就必须输入: a,hello

C语言变量命名

命名这块没什么好说的,重点就是不要带奇怪的运算符,严格区分大小写.

int a float b double c 前面是类型,后面是变量名,分隔莫忘 ; 号.

之后C语言就会在内存中开辟相应的空间.

C语言数据类型

1.基本数据类型 2.构造数据类型 3.指针类型 4.空类型四大类 在C语言的基本数据类型中的每一种数据都有明确的空间大小的分配(在同一编译环境下) 下面以一段代码为例子:

#include<stdio.h>
void main(){
	float a;//定义一个整型变量名为a
	printf("a所占的内存大小为%d字节",sizeof(a));

}

这里要注意一下C语言在较老的版本中是先执行定义的代码部分之后在执行相应的代码操作的比如

#include<stdio.h>
void main(){
	float a;//定义一个整型变量名为a
	printf("a所占的内存大小为%d字节",sizeof(a));
	int b;//再定义一个b是错误的,不过在最新的版本是可以的

}

之后在内存中就会出现这样的情况

在这里插入图片描述

如果此时我们在定义一个int b;就会在开辟一个具有两个字节的空间. 所以这里就引入了一个问题,当只需要两个字节的数据存入四个字节因该是没问题的但是让四个字节的东西存入两个字节的空间就会出现问题.所有我们可以得出一个结论,所占内存少的数据可以传入内存大的空间内,然而大的却不能存入小的,如果要传入就必须要丢失一些数据.而这就是C语言的自动转换和强制转换. 在这里插入图片描述

下面是一段代码(自动转换)

#include<stdio.h>
void main(){
	float a;
	int b=3;
	a=b;
	printf("a=%f,b=%d",a,b);
}

在这里插入图片描述 现在我们反一下

#include<stdio.h>
void main(){
	float a=3.00;
	int b;
	b=a;
	printf("a=%f,b=%d",a,b);
}

我们可以发现他发出来一个警告(警告不是错误最后可以运行,但是后果自负) 在这里插入图片描述 那么问题来了如何进行强制转换 只需将代码如下更改

b=(int)a

这里还需要注意的是 假设有a,b,c三个变量 b=(int)a + c 与 b= int (a+c)不等价

那么接下来的其数据类型将放到后面的博客中详细讲解,下面是基本数据结构的名称和使用范围.以vc2010为准 在这里插入图片描述 在这里插入图片描述

运算优先级与运算符

先看一张表 在这里插入图片描述 加减乘除等算数运算符>大小与关系运算符>逻辑运算符(不包括!)>条件运算符>赋值运算符>逗号运算符 什么是优先级,说白了就是在做运算时是先加减还是后乘除.就是这玩意一个运算是怎么算的,与数学的类似.比如先乘后加那么乘的优先级就高于加. 接下来就是几个栗子 (C语言中0为假,非零为真) 这里说明一下a++,与++a的区别,假设associate (a=3) 前者,返会结果为3此时a为4.后者将自加好的结果4返回.比如b=a++,c=++a,结果就是b=3,c=4

#include<stdio.h>
void main(){
	int a=1;
	int b=3;
	int c;
	printf("%d\n",!(a>b));//(a>b)返回为0,!时返回非零结果为1;
	printf("%d\n",-(b++));//等价与-(b++)
	printf("%d",!a&&b>5);//结果为零
}

接下来还要说的就是C语言中比较重要的位运算和三目运算 三目运算 表达式?a:b; 举个例子

#include<stdio.h>
void main(){
	int a=1;
	int b=3;
	int c;
	c=a>b?a:b;
	printf("c=%d",c);//结果为三,a>b为假所有返回第二个值b即3反之,c=a<b?a:b;返回第一个值a
}

位运算 这个可能不太友好,试着了解就好了.我会列举较为常用的规律. 先说说运算符号吧: &, | , ^(亦或), <<(左移), >>(右移)。 然后就是 原码,反码,补码. 对于一个正数三码合一,对于一个负数则要先转为补码再转为补码,之后使用补码运算. 下面举个例子; 原码: 在数值前直接加一符号位的表示法.对于8位二进制来说: (+7)原= 00000000 00000111 (-7)原= 10000000 00000111 反码: 正数的反码与原码相同. 负数的反码,符号位为“1”,数值部分按位取反. (+7)反= 00000000 00000111 (-7)反= 10000000 01111000 补码: 正数的补码和原码相同. 负数的补码则是符号位为“1”,数值部分按位取反后再在末位(最低位)加1.也就是“反码+1”. (+7)补=00000000 00000111 (-7)补=10000000 01111001

上面就是一个数字再内存中的存放情况,那么接下来就是运算了. 0&0=0 0&1=0 1&1=0

0|0=0 0|1=1 1|1=1

0^0=0 0^1=1 1^1=0

下面是几个例子 在这里插入图片描述 在这里插入图片描述

左右移动 在这里插入图片描述 在这里插入图片描述 关于这个记住一个口诀>>除,<<乘再取整数一个单位乘除2(记住是整数) int a=10; int b=10; printf("%d",a>>1)//结果为5 等价于 b=a/2; printf("%d",b) 即 a>>b 等价于 int c; c=a/(b*2)

C语言中的代码块

先看看这个一开始的问世程序,我们发现他们有一对花括号括起来,这一对花括号就是一个代码块,每个代码块的内存空间都是相对独立的.举个例子;

#include<stdio.h>
void main(){
	int a=3;
	int a=4;
	printf("a=%d",a);
	//将引发重定义的错误
}

在这里插入图片描述 但是这样:

#include<stdio.h>
void main(){
	int a=3;
	{
	int a=4;
	printf("a=%d\n",a);
	}
	printf("a=%d",a);
	//将引发重定义的错误
}

在这里插入图片描述 具体的原因我们可以看看下面的内存分布图 在这里插入图片描述 执行前面的那段代码时,我们主要看到栈区 在这里插入图片描述 这里区分一下

	int a=3;
	{
		a=4;
	}
	printf("a=%d",a);
	//没有载创建一个新的a 此时结果为4

条件语句

前面说了代码块,下面说条件就简单了. if()

if() { 里面有多条语句 } else() { 里面有多条语句 }

if() { 里面有多条语句 } else if() { 里面有多条语句 } else() { 里面有多条语句 } 下面时几个示例: 一.if语句

if (条件)
{
	//代码
}
else
{
	//代码
}
#include<stdio.h>
void main(){
	int year;
	scanf("%d",&year)
	int Februaryx;//闰年的二月
	if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
	{//只有一条语句,可以去掉花括号
		Februaryx = 29;
	}
	else
	{
		Februaryx = 28;
	}
	printf("%d\n", Februaryx);
}

还有更骚气的,判断学生的成绩

#include<stdio.h>
void main(){
	int score;
	printf("输入学生的成绩\n");
	//fprintf(stdout,"输入学生的成绩\n");
	scanf("%d",&score);
	
	if (score == 100)
	{
		printf("A\n");
	}
	else
	{
		if (score >= 90)
		{
			printf("B\n");
		}
		else
		{
			if (score >= 80)
			{
				printf("C\n");
			}
			else
			{
				if (score >= 70)
				{
					printf("D\n");
				}
				else
				{
					if (score >= 60)
					{
						printf("E\n");
					}
					else
					{
						printf("F\n");
					}
				}
			}
		}
	}

}
//C语言里面可以不用注重缩进,每条语句用 ; 隔开来就好了.(我主要是python写多了)

switch语句

看看上面的代码你就知道了有时候条件语句不见得好看.所以这里引入了一个新东西叫swith开关语句.

switch (变量或表达式) { case 值1: { //处理内容 break; } case 值2: { //处理内容 break; } default { //处理内容 break; } } 这里的变量可以是各种类型,但一般而言用得比较多的是 int and char

下面是一段代码注意注释; (判断一个月有几天,闰年的二月除外)

#include<stdio.h>
void main(){

int month;

int day;
scanf("%d",month);
switch (month)
{
	case 1:	
	{
		day = 31;
		printf("这个月有%d天",day);
		break;
	}
	case 2:
	{
		day = 28;
		printf("这个月有%d天",day);
		break;
	}
	case 3:
	{
		day = 31;
		printf("这个月有%d天",day);
		break;/*结束整条语句,如果没有break语句,则当month=3时就会往下继续执行直到整条语句结束.
		也就是说会输出 31,30,31,666


	*/
	}
	case 4:	
	{
		day = 30;
		printf("这个月有%d天",day);
		break;
	}		
	case 5:		
		day = 31;
		printf("这个月有%d天",day);
		break;
	}
	default:	//其它情况
	{
		day = 666;
		printf("这个月有%d天",day);
		break;
	}
}

}

循环

在语言中有三种循环 for(初始化变量;执行条件;变量变化){} while(执行条件){}

do{}while(执行条件); (最特殊的我认为就这个,人家后面有个; 然后先执行后判断) 下面时几个例子;

#include<stdio.h>

void main() {
	int i; 
	for(i=0;i<10;i++){
		printf("我认为博主很帅:\n");
		printf("同意人数%d\n",i);
	}
//最后i=10,运行十次
	printf("%d",i);//输出i的值
}

在这里插入图片描述 其执行顺序等价于

void main() {
	int i=0; 
	for(;i<10;){
		printf("我认为博主很帅:\n");
		printf("同意人数%d\n",i);
		i++;
	}
//最后i=10,运行十次
	printf("%d",i);//输出i的值
}

同理 while循环

#include<stdio.h>
int main() {
    int i=0;
    while(i<10){
        printf("我认为博主很帅:\n");
		printf("同意人数%d\n",i);
        i++;
	} 
}

do while循环

#include<stdio.h>
void main() {
    int i=0;
    do{
        printf("我认为博主很帅:\n");
		printf("同意人数%d\n",i);
        i++;
      } while(i<10);
}

函数

函数这玩意要说的可多可少,扯远了就要扯一下函数指针.入门篇就先不写那么多了. 首先时函数的位置,这里时在前面(main函数前) 举个例子

void print (int i){//函数返回值为空,int i 为形式参数

	printf("我认为博主很帅:\n");
	printf("同意人数%d\n",i);

}
/*第一点自定义函数不要与系统函数重名,第二点注明返回类型,一个C语言项目中只允许存在一个main函数*/
#include<stdio.h>
void main() {
    int i=0;
    do{
		print(i);
        i++;
      } while(i<10);
	printf("%d",i);
}

如果在后面就必须声明 如:


/*第一点自定义函数不要与系统函数重名,第二点注明返回类型,一个C语言项目中只允许存在一个main函数*/
#include<stdio.h>
void main() {
	void print (int i);//声明函数,其实这也是一个头文件里面的内容
    int i=0;
    do{
		print(i);
        i++;
      } while(i<10);
	printf("%d",i);
}

void print (int i){//函数返回值为空,int i 为形式参数

	printf("我认为博主很帅:\n");
	printf("同意人数%d\n",i);

}

头文件

都说到函数不谈谈头文件就废了 这玩意就是为了更好的管理自己写的函数准备的. 在这里插入图片描述 现在,我们将我们先前写的函数放入一个文件中 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 最后代码就是这样

#include"print_myself.h"/*导入自定义头文件用""此方法也可以导入系统的头文件
只是相对而言用<>导入效果更好*/
#include<stdio.h>
void main() {
    int i=0;
    do{
		print(i);
        i++;
      } while(i<10);
	printf("%d",i);
	getchar();
}

关于C语言后面还有指针,数组,结构体,共用体,基本文件操作..