Skip to content

Latest commit

 

History

History
executable file
·
1229 lines (939 loc) · 27.9 KB

编程入门.md

File metadata and controls

executable file
·
1229 lines (939 loc) · 27.9 KB

编程入门

编程是一种控制计算机的方式,和我们平时双击打开文件、关机、重启没有任何区别——闫学灿

一、初窥C语言

1.程序结构剖析

我们先看看上边的那个代码的结构,我们用左边的行号来表示第几行

1、第1行#include<stdio.h>

这一行称之为头文件,其结构形式为#include<中间填调用的头文件>

这里我们调用的头文件为stdio.h,这个头文件中包含着最常用的函数

头文件中包含着特定的函数,函数调用的结构为函数名+(),这里调用的是printf()函数,作用是输出特定数值。

如果需要使用特定的函数,就需要加入特定的头文件,一个头文件中包含着多个函数

常见头文件: math.h, algorithm, stdio.h

2、第3行int main()

这是主函数,所有的程序都是从主函数开始,也是从主函数结束,函数的内容使用大括号{}包裹起来

每个c语言代码都要包含这个函数

3、第5行printf("Hello world\n");

这是一个==语句==,调用了头文件stdio.h中的printf函数。

printf函数在这里的使用:

输出字符串(一串字符),使用双引号扩起来。末尾的\n,表示换行符,下边我们会讲到。

比较两个代码输出的异同

#include<stdio.h>

int main()
{
	printf("hello world");
	printf("你好世界");
	return 0;
}
#include<stdio.h>

int main()
{
    printf("hello world\n");
    printf("你好世界");
    return 0;
}

==语句==的特点:要以;结尾。注意:c语言中所有的符号均为英文符号,使用中文符号代码将无法运行

4、第6行return 0;

函数的返回值,除了void的类型的函数(这里的main函数是int类型函数)其余函数都需要返回值,这个知识点我们会在==函数==一节中详细讲解

5、第8行//该程序用于输出字符串Hello World

这一行为==注释==,注释的内容将不会被编译器识别,也就是说,注释中写任何内容都不会影响程序的运行

注释的类型:

单行注释:

//注释内容

多行注释:

/*注释内容
注释内容
注释内容*/

如上:该代码的每一行均已讲解完成

2.数据类型、变量和常量

(1)、C语言中的数据类型:

1、整型:表示整数的数据类型

数据类型 占用空间 取值范围
short(短整型) 2字节 -2^15^~2^15^-1
int(整型) 4字节 -2^31^~2^31^-1
long(长整型) 4字节 -2^31^~2^31^-1
long long(长长整型) 8字节 -2^63^~2^63^-1

int是最常用的整型

2、实型(浮点型):表示小数的数据类型

数据类型 占用空间 有效数字范围
float 4字节 7位有效数字
double 8字节 15~16位有效数字

double是最常用的整型

3、字符型:表示单个字符的数据类型

数据类型 占用空间
char 1字节

4、布尔类型:表示正确或错误的数据类型

数据类型 占用空间
bool 1字节

bool型存在两种,true(1)flase(0),分别表示正确和错误

其他相关:

转义字符:

转义字符 含义 ASCII码值(十进制)
\a 警报 007
\b 退格(BS),将当前位置移到前一列 008
\f 换页(FF),将当前位置移到下页开头 012
\n 换行(LF),将当前位置移到下行开头 010
\r 回车(CR),将当前位置移到本行开头 013
\t 水平制表(HT)(跳到下一个TAB位置) 009
\v 垂直制表(VT) 011
\ 代表一个反斜字符“\” 092
\’ 代表一个单引号(撇号)字符 039
\” 代表一个双引号字符 034
? 代表一个问号 063
\0 数字0 000
\ddd 8进制转义字符,d范围0~7 0位8进制
\xhh 16进制转义字符,h范围09,af,A~F 3位16进制

sizeof关键字

如果忘了数据类型的大小,就可以使用sizeof(数据类型\变量)来查看,显示的是字节数

#include<stdio.h>

int main()
{
    int a;
    printf("%d\n",sizeof(int));
    printf("%d\n",sizeof(a));
    return 0;
}

(2)、变量和常量

变量是可变的量,其创建语法为数据类型 变量名;或者数据类型 变量名 = 变量初始值;

变量在创建之后可以再通过赋值改变其存储的值

#include<stdio.h>

int main()
{
    int a;
    int b = 10;
    a = 5;
    printf("%d\n",a);//先不用管括号中的含义,这里的意思是输出a,下边一行是输出b
    printf("%d\n",b);
    return 0;
}

常量是创建之后就不可更改的量,所以常量的创建一定要对其赋予初始值

常量创建有两种方式:

1、#define宏常量:#define 常量名 常量值

2、const修饰的变量:const 数据类型 常量名 = 常量值;

#include<stdio.h>

int main()
{
    #define a 10
    const int b = 20;
    printf("%d\n",a);
    printf("%d\n",b);
    return 0;
}

(3)、标识符(变量和常量名和函数名等)的命名规则

  • 标识符不能是关键字

  • 标识符只能由字母、数字、下划线组成

  • 第一个字符必须为字母或下划线

  • 标识符中字母区分大小写

注意:命名争取做到顾名思义的效果,方便阅读。

3.数据的输入与输出

c语言中的格式符:

%d整型输出,%ld长整型输出,

%o以八进制数形式输出整数,

%x以十六进制数形式输出整数,或输出字符串的地址。

%u以十进制数输出unsigned型数据(无符号数)。

%c用来输出一个字符,

%s用来输出一个字符串,

%f用来输出实数,以小数形式输出,默认情况下保留小数点6位。

%.100f用来输出实数,保留小数点100位。

%e以指数形式输出实数,

%g根据大小自动选f格式或e格式,且不输出无意义的零。

常用的就是%d,%lf,%c,%s这四个

输入:scanf("格式符",&变量名);

#include<stdio.h>

int main()
{
    int a;
    double b;
    scanf("%d%lf",&a,&b);
    return 0;
}

输出:printf("格式符",变量名);

#include<stdio.h>

int main()
{
    int a;
    double b;
    scanf("%d%lf",&a,&b);
    printf("%d %f",a,b);//两数之间会有一个空格
    return 0;
}

4.运算符

1.算数运算符

算法运算符包含以下符号:

运算符 术语 示例 结果
+ 正号 +3 3
- 负号 -3 -3
+ 10+5 15
- 15-5 5
* 10*5 50
/ 10/5 2
% 取模(取余) 10%3 1
++ 前置递增 a=2;b=++a; a=3;b=3;
++ 后置递增 a=2;b=a++; a=3;b=2;
-- 前置递减 a=2;b=--a; a=1;b=1;
-- 后置递减 a=2;b=a--; a=1;b=2;
#include<stdio.n>

int main()
{
    int a = 10,b = 5,c = 3;
    double d = 3.14,e = 5.34;
    int num1 = a - b;
    double num2 = e - d;
    double num3 = a / 3;
    printf("%d %f %f\n",num1, num2, num3);
    int num4 = a % 10;
    printf("%d\n",num4);
    return 0;
}
#include<stdio.h>

int main()
{
    int a = 10;
    printf("此时a的值为:%d\n",a);
    a++;
    printf("此时a的值为:%d\n",a);
    a--;
    printf("此时a的值为:%d\n",a);
    ++a;
    printf("此时a的值为:%d\n",a);
    --a;
    printf("此时a的值为:%d\n",a);
    return 0;
}

前置与后置的区别

#include<stdio.h>

int main()
{
    int a = 10;
    printf("此时a的值为:%d\n",a++);
    printf("此时a的值为:%d\n",a);
    printf("此时a的值为:%d\n",++a);
    return 0;
}

2.赋值运算符

赋值运算符包括以下几个符号:

运算符 术语 示例 结果
= 赋值 a=2;b=3; a=2;b=3;
+= 加等于 a=0;a+=2; a=2;
-= 减等于 a=2;a-=3; a=-1;
*= 乘等于 a=2;a*=2; a=4;
/= 除等于 a=4;a/=2; a=2;
%= 模等于 a=3;a%=2; a=1;
#include<stdio.h>

int main()
{
    int a = 10;//赋值
    printf("此时a的值为:%d\n",a);
    a += 5;
    printf("此时a的值为:%d\n",a);
    a *= 3;
    printf("此时a的值为:%d\n",a);
    a /= 3;
    printf("此时a的值为:%d\n",a);
    a %= 2;
    printf("此时a的值为:%d\n",a);
    return 0;
}

3.比较运算符

比较运算符有以下符号:

运算符 术语 示例 结果
== 相等于 4 == 3 0
!= 不等于 4 != 3 1
< 小于 4 < 3 0
> 大于 4 > 3 1
<= 小于等于 4 <= 3 0
>= 大于等于 4 >= 3 1

比较运算符返回的是bool型数据

#include<stdio.h>

int main()
{
    int a = 10,b = 10,c = 5;
    printf("a == b:%d\n",a == b);
    printf("a != b:%d\n",a != b);
    printf("a > b:%d\n",a > b);
    printf("a < b:%d\n",a < b);
    printf("a >= b:%d\n",a >= b);
    printf("a <= b:%d\n",a <= b);
    return 0;
}

4.逻辑运算符

逻辑运算符有以下符号:

运算符 术语 示例 结果
! !a 如a为真,则!a为假;如a为假,则!a为真
&& a && b 如a和b都为真,则结果为真,否则为假
|| a || b 如果a和b有一个为真,则结果为真,二者都为假时,结果为假
#include<stdio.h>

int main()
{
    bool a = true,b = false;
    printf("!a=%d\n",!a);
    printf("a&&b=%d\n",a&&b);
    printf("a&&a=%d\n",a&&a);
    printf("b&&b=%d\n",b&&b);
    printf("a||a=%d\n",a||a);
    printf("a||b=%d\n",a || b);
    printf("b||b=%d\n",b||b);
    return 0;
}

二、程序流程结构

程序流程结构分为三种:选择结构、循环结构和跳转语句

1.选择结构

if语句

if(条件)
{
	代码	
}
else if(条件)
{
    代码
}
else 
{
    代码
}
#include<stdio.h>

int main()
{
    int a = 2;
    if(a == 1)
    {
        printf("a=%d\n",a);
    }
    else if(a == 2)
    {
        printf("a=%d\n",a);
    }
    else 
    {
        printf("a即不等于1也不等于2\n");
    }
    return 0;
}

三目运算符

表达式1?表达式2:表达式3

#include<stdio.h>

int main()
{
    int a = 3;
    a==3?printf("a==3"):printf("a!=3");
    return 0;
}

switch语句

switch(表达式)
{
    case结果1:执行语句;break;
	 
	case结果2:执行语句;break;
	 
	……
    
    default:执行语句;break;	 
}
#include<stdio.h>

int main()
{
    int a = 3;
    switch(a)
    {
        case a== 1:
            printf("a==1\n");
           	break;
        case a==2:
            printf("a==2\n");
           	break;
        case a==3:
            printf("a==3\n");
           	break;
        default:
            printf("a的值未知\n");
            break;
    }
    return 0;
}

2.循环结构

while循环

while(循环条件){循环语句}

#include<stdio.h>

int main()
{
    int n = 10;
    while(n--)
    {
        printf("%d\n",n);
    }//输出10~0
    return 0;
}

do……while循环

do{循环语句}while(循环条件);

#include<stdio.h>

int main()
{
    int n = 10;
    do{
        printf("%d\n",n);
    }while(n--);//输出10~0
    return 0;
}

while和do……while的区别

  • while是先判断循环条件再执行循环语句;do……while是先执行循环语句再判断循环条件
  • do……while至少会执行一次

for循环

for(起始表达式;条件表达式;末尾循环体){循环语句;}

#incldue<stdio.h>

int main()
{
    for(int i = 0;i < 10;i++)
    {
        printf("%d\n",i);
    }//输出0~9
    return 0;
}

嵌套循环

嵌套循环就是在循环中再套一层循环,下边是冒泡排序

#include<stdio.h>

int main()
{
    int lenth = 10;
    int a[10] = {9,8,8,10,4,6,1,7,5,3};
    for(int i = 0;i < lenth - 1;i++)
    {
        for(int j = 0;j < lenth - 1 - i;j++)
        {
            if(a[j] > a[j + 1])
            {
                int temp = a[j];
                a[j] = a[j + 1];
                a[j + 1] = temp;
            }
        }
    }
    for(int i = 0;i < lenth;i++)
    {
        printf("%d "a[i]);
    }
    return 0;
}

3.跳转语句

跳转语句的作用在于跳出循环。

break语句

break语句用于跳出循环结构

#include<stdio.h>

int main()
{
    for(int i = 2;i <= 100;i++)
    {
        bool flag = 1;
        for(int j = 2;j < i;j++)
        {
            if(i % j == 0)
            {
                flag = 0;
                break;
            }
        }
        if(flag)
            printf("%d\n",i);
    }
    return 0;
}//输出100以内的素数(质数)

continue语句

continue语句用于跳过本次循环

#include<stdio.h>

int main()
{
    int res = 0;
    for(int i = 1;i < 10;i++)
    {
        if(i == 3)
            continue;
        res += i;
    }
    printf("%d\n",res);
    return 0;
}//求1,2,4,5,6,7,8,9的和

goto语句

这个不讲,没用

三、数组

数组是一个存放了相同类型元素的集合

**特点1:**数组中每个数据元素都是相同的数据类型

**特点2:**数组是由连续的内存位置组成的

**特点3:**数组的下标是从0开始的

1.一维数组

一维数组的定义方式

  • 数据类型 数组名[ 数组长度 ];
  • 数据类型 数组名[ 数组长度 ] = {值1,值2…};
  • 数据类型 数组名[ ] = {值1,值2…};

一维数组定义

#incldue<stdio.h>

int main()
{
    int a[5];//没有初始值的数组会被随机赋值
    int b[5]={1,2,3,4,5};
    int c[]={1,2,3,4,5};
    for(int i = 0;i < 5;i++)
	{
		printf("%d ",a[i]);	
	} 
	printf("\n");
	for(int i = 0;i < 5;i++)
	{
		printf("%d ",b[i]);	
	} 
	printf("\n");
	for(int i = 0;i < 5;i++)
	{
		printf("%d ",c[i]);	
	} 
	printf("\n");
    return 0;
}

一维数组的赋值

#include<stdio.h>

int main()
{
    int a[5];
    for(int i = 0;i < 5;i++)
    {
        a[i] = i;
    }
    for(int i = 0;i < 5;i++)
    {
        printf("%d ",a[i]);
    }
    printf("\n");
    for(int i = 0;i < 5;i++)
    {
        scanf("%d",&a[i]);
    }
    for(int i = 0;i < 5;i++)
    {
        printf("%d ",a[i]);
    }
    printf("\n");
    return 0;
}

字符串初识

顾名思义,字符串就是一串字符。数组的一个特点就是由连续的内存地址组成,所有字符类型的数组可以用于存储字符串。

#include<stdio.h>

int main()
{
    char str[10];//最长可以储存9位长度的字符串
    scanf("%s",str);
    printf("%s\n",str);
    return 0;
}

字符串输入的特殊之处:

其他数据类型 字符串类型
scanf("%d",&a); scanf("%s",a);

在变量名前少了&

关于字符&

该字符用于取变量的内存地址,输入的时候是将值放入一个内存地址当中,所以在输入的时候需要加上&(关于这个知识点详细的可以去学学指针)

这就引出数组的一个特性,==数组命名代表着数组在内存中的首地址,故输入字符串不需要取值符&==。

关于字符串,我们会单独开一节来讲,这里知识简单的提及一下。了解了不用加&和想要存储n位长度的字符串就要开至少n+1长度的数组即可,后边会讲原因。

2.二维数组

二维数组的创建就是数组名后两个中括号即可

#inlcude<stdio.h>

int main()
{
    int a[5][5];
    for(int i = 0;i < 5;i++)
    {
        for(int j = 0;j < 5;j++)
        {
            scanf("%d",&a[i][j]);
        }
    }
    for(int i = 0;i < 5;i++)
    {
        for(int j = 0;j < 5;j++)
        {
            printf("%d ",a[i][j]);
        }
        printf("\n");
    }
}

3.多维数组

多加几个中括号就可以了

四、字符串

字符串就是字符的数组

字符串在字符数组中的储存方式:

例如,我们将Hello这个词存入到字符串数组str中,那么就会有:

下标 0 1 2 3 4 5
str H e l l 0 \0

我们在上边提到过,==想要存储n位长度的字符串就要开至少n+1长度的数组==,原因就在这里,字符串的最后一位存储着转义字符\0,作为字符串的结尾。在字符串输出的时候,\0不会输出。

字符串的创建与初始化:

  • char str[6] = "Hello";(一定要用双引号)
  • char str[] = "hello";
  • char str[6];(在不进行初始化时,一定要规定长度)

字符串的输入:

  • scanf("%s",str);

字符串处理函数:

加入头文件string.h

==字符串连接函数==:strcat(字符串1,const 字符串2);//将字符串2连接到字符串1的后边

==字符串复制函数==:strcpy(字符串1,cosnt 字符串2);//将字符串2赋值给字符串1

==字符串比较函数==:strcmp(const 字符串1,const 字符串2);//如果字符串1等于字符串2,函数值为0;如果字符串1大于字符串2, 函数值为一正整数;如果字符串1小于字符串2,函数值为一负整数。(比较字典序列大小)

==字符串长度函数==:strlen(const 字符串);//函数值为字符串的实际长度,不包含转义字符\0在内。

五、函数

函数就是将一段代码封装起来,通常是封装一个程序中会重复使用的较长的代码,合理使用函数可以提高代码的精简度和可读性

1.函数定义的语法

返回值类型 函数名 (参数列表)
 {
     函数体语句;

     return表达式;
}

返回值类型即为数据类型和一个空类型void(无返回值)

2.函数的调用

函数名(参数)

#inlcude<stdio.h>

int add(int num1,int num2)//两数之和
{
    int num = num1 + num2;
    return num;
}

int main()
{
    int a,b;
    scanf("%d%d",&a,&b);
    printf("%d",add(a,b));
    return 0;
}

由于编译器在编译的时候是从上往下一行一行编译的,所以==函数必须要写在其调用前边==。

如果想要把函数写在后边就得先进行声明

#include<stdio.h>

int add(int num1,int num2);//函数声明

int main()
{
    int a,b;
    scanf("%d%d",&a,&b);
    printf("%d",add(a,b));
    return 0;
}

int add(int num1,int num2)//两数只和
{
    int num = num1 + num2;
    return num;
}

3.函数的参数类型

值传递

调用形式参数(简称形参)的为值传递,只传递该参数的值,故在函数中调用形式参数时不会影响实际参数

#include<stdio.h>

int add(int a,int b)
{
    a--,b--;
    printf("传入参数的值为:a=%d b=%d\n",a,b);
    return a + b;
}

int main()
{
    int a = 5,b = 10;
    printf("函数的返回值:%d\n"add(a,b));
    printf("实际参数的值: a=%d b=%d\n",a,b);
}

地址传递

调用**实际参数(简称实参)**的为地址传递,地址传递会改变实参的值

#include<stdio.h>

int add(int &a,int &b)
{
    a--,b--;
    printf("传入参数的值为:a=%d b=%d\n",a,b);
    return a + b;
}

int main()
{
    int a = 5,b = 10;
    printf("函数的返回值:%d\n"add(a,b));
    printf("实际参数的值: a=%d b=%d\n",a,b);
}

为什么地址传递会改变实际参数的值?(指针初识)

当值传递时:

另外开辟了一个内存用于存储值,故形式参数改变时不会影响实际参数

当地址传递时:

地址传递时,参数直接指向了同样一个地址,故参数改变时,实际参数也会跟着改变

4.函数的分文件编写

这个了解一下就可以

函数分文件编写一般有4个步骤

  1. 创建后缀名为.h的头文件

  2. 创建后缀名为.cpp的源文件

  3. 在头文件中写函数的声明

  4. 在源文件中写函数的定义

5.函数封装冒泡排序

#include<stdio.h>

void sort(int a[],int lenth)
{
    for(int i = 0;i < lenth - 1;i++)
    {
        for(int j = 0;j < lenth - 1 - i;j++)
        {
            if(a[j] > a[j + 1])
            {
                int temp = a[j];
                a[j] = a[j + 1];
                a[j + 1] = temp;
            }
        }
    }
}

int main()
{
    int a[10] = {9,8,8,10,4,6,1,7,5,3};
    sort(a,10);
    for(int i = 0;i < 10;i++)
        printf("%d ",a[i]);
    return 0;
}

六、结构体

结构体属于用户自定义的数据类型,允许用户存储不同的数据类型

1.结构体的定义与使用

结构体定义:struct 结构体名 {结构体成员列表};

#include<stdio.h>

struct People
{
	char name[10];
	int age;
};

int main()
{
	People p;
	scanf("%s",p.name);
	scanf("%d",&p.age);
	printf("姓名为:%s\n年龄为:%d",p.name,p.age);
	return 0;
}

2.结构体数组

结构体数组的定义:结构体名 变量名[ ];

#include<stdio.h>

struct People
{
	char name[10];
	int age;
};

int main()
{
	People p[4];
	for(int i = 1;i <= 3;i++)
    {
        scanf("输入第%d个人的名字:%s",p[i].name);
        scanf("输入第%d个人的年龄:%d",&p[i].age);
    }
    for(int i = 1;i <= 3;i++)
    {
        printf("第%d个人的名字:%s\n",p[i].name);
        printf("第%d个人的年龄:%d\n\n",p[i].age);
    }
	return 0;
}

七、指针

指针是c语言直接访问内存的一种方式

  • 内存编号是从0开始记录的,一般用十六进制数字表示
  • 可以指针变量保存地址

1.指针的使用

指针变量的定义:数据类型 * 变量名 = &另一个变量名

指针变量的变量名中存储的是地址,在变量名之前加上*解引用,则是地址

一般变量和指针变量的区别:就像一枚硬笔的两面

变量 地址
一般变量 &a a
指针变量 a *a
#include<stdio.h>

int main()
{
    int a = 10;
    int *p = a;
    printf("a=%d &a=%d\n p=%d *p=%d",a,&a,p,*p);
    return 0;
}

2.空指针与野指针

**空指针:**指针变量指向内存中编号为0的空间。空指针指向的空间是用户不可访问的,其作用是初始化指针。

**野指针:**指针指向非法的内存空间。

3.const修饰指针

1.常量指针:const 数据类型 * 变量名 = &另一个变量名

特点:指针的==指向是可以改,但是指向的值不可以改==。

2.指针常量:数据类型 * const 变量名 = &另一个变量名

特点:指针的==指向不可以改,但指针指向的值可以改==。

3.const即修饰指针,又修饰常量:const 数据类型 * const 变量名 = &另一个变量名

特点:指针的==指向和指向的值都不可以改==。

4.指针与数组

指针访问一维数组:

#include<stdio.h>

int main()
{
    int a[5] = {1,2,3,4,5};
    int *p = a;
    for(int i = 0;i < 10;i++)
    {
        printf("%d ",*(p + i));
    }
    return 0;
}

指针的加减:

如上程序,int类型的指针+1之后,内存地址编号增加了4,即向后移动了4个字节

我们知道,数组的空间是连续的,向后移动四个字节就到达了数组的下一个元素

指针访问二维数组:

#include<stdio.h>

int main()
{
    int a[5][5] = {{0,1,2,3,4},
                   {5,6,7,8,9},
                   {0,1,2,3,4},
                   {5,6,7,8,9},
                   {0,1,2,3,4}};
    int (*p)[5] = a;//指针声明
    for(int i = 0;i < 5;i++)
    {
    	for(int j = 0;j < 5;j++)
    	{
    		printf("%d ",*(*(p + i) + j));
		}
		printf("\n");
	}
    return 0;
}

指针p的指向是数组a的开头地址,即a[0] [0],p + 1指向的是a[1] [0],即第二行的开头地址

如果你想访问a[0] [1]则是:*(p) + 1

访问a[1] [1]:*(p + 1) + 1

不要问我为什么,要问就去问Dennis MacAlistair Ritchie老爷子,他就是这么规定的

5.指针与函数

用指针最为函数参数,传递实参的地址,会修改实参

#include<stdio.h>

void sort(int *a, int lenth)
{
    for(int i = 0;i < lenth - 1;i++)
    {
        for(int j = 0;j < lenth - 1 - i;j++)
        {
            if(a[j] > a[j + 1])
            {
                int temp = a[j];
                a[j] = a[j + 1];
                a[j + 1] = temp;
            }
        }
    }
}

int main()
{
    int a[10] = {9,8,8,10,4,6,1,7,5,3};
    int lenth = 10;
    sort(a,lenth);
    for(int i = 0;i < lenth;i++)
    {
        printf("%d ",a[i]);
    }
    return 0;
}