一文搞懂C语言-----C语言快速入门

数据类型

变量

变量三要素:

  • 名称(标识符)
  • 变量位置(&变量名)
  • 变量的值

变量用",“表示分隔,用”;"表示结束

int----整型----格式说明----%d十进制整型,%o八进制整型,%x十六进制整型

float----实型----格式说明----%f实型

char---- 字符型----格式说明----%c字符型,%s字符串

%4d 输出结果占4个空位,右对齐,不够补空格

%-4d 输出结果占4个空位,左对齐,不够补空格

#include<stdio.h>
void main()     //主函数
{
}

整型常量

八进制数:以0开头(010,012)

十六进制数:以0x开头(0x10,0x12,0x22)

实型常量

  1. 小数形式,如 3.14,-9.8
  2. 指数形式,如

1.2x10^5==1.2E(e)+5

3.14x10^9==3.14E+9

9.8x10^3==9.8e+3

%e—指数形式输出,%f—小数形式输出,%g—选择%f%e只输出列最小的输出,并去掉无意义的0。

转义字符

  • \n----换行
  • \t----横向跳格
  • \b----退格
  • \r----回车
  • \'或\"----输出单引号或双引号
  • \\----输出斜杠

注意: ‘a’,‘b’-----注单引号中只能有一个字符,‘a’,‘ab’

ASCLL码

a---->97,A---->65,0---->48,空格---->32

符号常量

#include<stdio.h>
# define pi 3.14
void main()
{
    …………
    s=pi+a+b     //将pi自动替换为3.14
    …………
}

运算符

优先级

逻辑非(!) > 乘除,取余 > 加减 > 大于,小于,大于或等于,小于或等于 > 等于,不等于 > 逻辑与(&&) > 逻辑或(||) > 赋值运算符(=)

C语言中的除运算(/)是整除,例如:5/2=2(舍去小数部分);%(取余):要求两边的操作数均为整数。

算术运算符(加减乘除等)>赋值运算符(用"=“表示,”="右边的值赋值给左边)

a=12,a+=,a-=,a * a,求a=?

解:

a * a=12x12=144,a=a-144=-132,a=a+(-132)=-132-132=-264

.7== 0.7 , 12.== 12.0 , .8==0.8

自加与自减

自加:  int i=10;
       j=++i;(先让i自增,再参与运算)
       j=i++;(i先参与运算,再自增)
       
自减:  int i=10;
       j=--i;(先让i自减,再参与运算)
       j=i--;(i先参与运算,再自减)

关系运算符

等号(==),不等号(!=)

C语言中用整数"1"表示逻辑真,用整数"0"表示逻辑假

(&&), (||), (!)

C语言中, 0,0.0,'\0',NULL都为假,其余均为真

"a" && 2 该表达式为真

逻辑与优化

int a=0, b=0;
int i=a && ++b;

//结果:i=0,a=0,b=0(++b被优化了,不作运算)

逻辑或优化

int a=1, b=0;
int i=a || ++b;

//结果:i=1,a=1,b=0(++b被优化了,不作运算)

条件语句

switch

switch(表达式)
{
    case 常量表达式1:语句序列; break;   //执行的语句如printf
    case 常量表达式2:语句序列; break;
    case 常量表达式3:语句序列; break;
    case 常量表达式4:语句序列; break;
    case 常量表达式5:语句序列; break;
    default : 语句序列; break;
}

//表达式的值满足哪个常量表达式就执行哪个表达式后的语句,
//都不满足就执行默认后的语句

if—else

if(表达式1)
{
    执行语句1;
}
else if(表达式2)
{
    执行语句2;
}
else
{
    执行语句3;
}
//表达式1为真时执行语句1;表达式2为真且表达式1为假时执行语句2;
//否则执行语句3

循环

while循环

image.png

while(表达式)
 执行语句;

//当表达式为真时,就一直循环执行语句

do–while循环

image.png

do
{
    执行语句;
}
while(表达式);

//当表达式为真时,就一直循环执行语句,表达式为假时,
//则只会执行一次

for 循环

image.png

for(表达式1;表达式2;表达式3)
{
    执行语句;
}

函数

库函数

val=getchar() 输入一个字符将其存入变量val中(无参函数)

gets(val)输入字符串,将其存入val变量中

putchar('a')输出一个字符’a’(有参函数)

puts('abc')输出字符串’abc’(有参函数)

pow(x,y)获得x的y次方的值

用户自定义函数

函数类型标识符—int,float,char等,表示返回值的类型

return 将值返回给主调函数

函数类型标识符 函数名(参数类型 参数名,……)  //函数头
{
    执行语句       //函数体
}

函数调用

主调函数

主调函数:主动去调用别的函数(其中参数叫实参)

函数类型标识符 变量名=函数名(参数1,参数2); //主调函数

例如:int val=Add(2,4);

被调函数

被调函数:被调用的函数本身(其中参数叫形参)

形参的改变,对应的实参不受影响,实参--单向值传递--->形参

注意:若主调函数在被调函数之前,则需要提前声明(即在主调函数之前,将定义的函数头,写出来)

#include<stdio.h>

int Add(int a,int b);  //函数声明
int main()
{
    int a=2,b=4,c=0;
    c=Add(a,b); //调用函数(主调函数)
    printf("结果为:%d",c);
    
    return 0;
}

int Add(int a,int b)   //函数定义(被调函数)
{
    return a+b;
}

数组

数组:将相同类型的有限个数据排列在一起的集合。

一维数组

数组元素类型 数组名[数组大小(此处必须是个常量)]={数据1,数据2,数据3……}

int Array[4]={120,340,65,97};

//调用数组中的某个元素
Array[下标];        //数组的下标从0开始
//Array[2] 表示Array数组第三个元素,即65

数组中未定义的元素默认为0;

在用户自定义函数中,若将数组名作为实参,对应的形参是数组形式(形参名[ ]),则形参变换,实参要跟着变换,实参--双向地址传递--->形参

二维数组

类型说明符 数组名[常量表达式1][常量表达式2];

float array[4][2]; //共4行2列,有4x2个元素

int array[2][3]={{1,2,3},{4,5,6}};
               ={1,2,3,4,5,6};
               
 //元素全部赋值时,数组第一维长度可以省略,第二维长度不能省略
 // array[][3];  这种写法可以用于形参与数组数组初始化,
                 //但不能用于定义

字符串

char 数组名[整型常量表达式]; //char array[20];

字符串初始化

  • 对元素逐个赋值: char array[5]={'c','h','i','n','a'};
  • 字符串赋值:char array[6]="china";(注意:这里数组长度要比可见字符多一个,这个多的长度是用来存放'\0','\0'表示字符串的结束,自动添加)
  • C 语言中一个中文字符占2个字节: char array[]="张三" (数组长度为5)

scanf函数可以直接使用字符数组(字符串)s,不需要在前面添加&符号

scanf("%s",s);<----->scanf("%s",&s[0]);

char s[]="I love\0 china";
printf("%s",s);
//打印的结果为"I love",原因:输出字符时遇见了'\0',提前终止了

gets(s); //输入字符串到s中,且自动在输入末端加上'\0',
         //等价为scanf("%s",s);
puts(s); //输出字符串s,且自动在末端加上'\n'

字符串相关函数

头文件:#include<string.h>

字符串不能通过"="来赋值

strcpy(目标字符地址,源字符地址);
strncpy(目标字符地址,源字符地址,要复制的字符个数);
//strcpy():将源字符串包括结束符'\0'一同复制到目标字符所在地址的
//内存里

//strncpy():作用同上,但是是将源字符的前n个字符复制到目标字符所在
//地址的内存中,且不会复制结束符'\0',因此使用此函数后面最好加上
//'\0',否则可能出现乱码

strcat(目标字符地址,源字符地址);
//strcat()将源字符串连接到目标字符串后面,自动删除原目标字符串
//的'\0',将源字符串连同结束符'\0'一起放到目标字符串后面

strcmp(字符串1地址,字符串2地址);
//strcmp():将两个字符串中对应的字符的ASCLL码依次对比,
//直到不相等或比较到其中一个字符串的末尾为止

//若字符串1>字符串2,则函数结果为1
//若字符串1=字符串2,则函数结果为0
//若字符串1<字符串2,则函数结果为-1

字符的其他等价表示

char c;
c='a';
=97  //'a'的ASCLL码为97
='\141' //八进制数141==十进制数97
='\x61'  //十六进制数61==十进制数97

//'\ddd':ddd处是1~3位八进制数所代表的字符
//'\xhh':hh处是1~2位十六进制数所代表的字符

指针基础

指针变量:专门存放变量地址的变量
(类比整型变量:专门存放整型数据的变量)

类型说明符 * 指针变量名

int *pt  //表示指向一个整型数据的变量
//该变量名为pt

int n=99,*p; p=&n;//指针p指向了变量n的地址
//等价为int *p=&n;
//这里的*p就是指针

printf("%d\n",*p);
printf("%d\n",n);
//两者等价

*p=20; //将*p指针指向的地址所对应的变量赋值为20

char *a[10];   //存放了10个字符指针(指针数组)

C语言中,指针的大小都是4个字节

在数组中,两个指针相减(相加),所得结果是两个指针所指数组元素下标之差(指针一定要赋值后才能使用)

多级指针:

int *q,**p,i=99;
q=&i;
p=&q;
//*q指向变量i的地址,**p指向指针*q本身所在的地址

指针作为形参的函数调用时,是双向地址传递即形参影响实参

*p==p[0],**p==p[0][0];

指针与数组:

for(i=0;i<6;i++)
{
    printf("%d\n",*(p+i));
    printf("%d\n",p[i]);
    printf("%d\n",*p++);
    //三者结果是相同的
}


char *ch;  //指针初始时指向数组的第一个元素
ch="hello!";  //字符串ch
char *s[]={"Cprogram","BASIC",
        "computer English","Word"};
//字符串指针数组*s
char **p;
for(p=s,p<s+4,p++)
{
    printf("%s\n",*p);
}
//*(*p+1)=='p'
//**(p+1)=='B'
//上面的两句注释一定要弄清楚两者区别

image.png

指针与二维数组

image.png

int s[3][4]={{0,2,4,6},{1,3,5,7},{9,6,2,1}};

int (*p)[4],i,j; //这里的*p只能指向每
                //一行只有4个元素的数组
p=s;
scanf("%d%d",&i,&j);
printf("s[%d][%d]=%d\n",i,j,*(*(p+i)+j));

//输入1,2  输出s[1][2]=5

//*(p+i)==s[i]
//*(*(p+i)+j)==*(s[i]+j)==s[i][j]

a[2][3]=*(*(a+2)+3) //只有一级指针才能存放元素地址

image.png

p++=30(看为(p++))

++p=21(看为++§)

函数的调用

函数的嵌套调用

嵌套调用:在执行一个函数的过程中又去调用另一个函数,调用完后会返回第一个函数中继续执行之前未执行的内容

函数递归调用

直接递归:在执行一个函数的过程中,又去调用这个函数本身一次

间接递归:在执行一个函数的过程中,又去调用另一个函数,在执行另一个函数时,又去调用第一个函数,调用完后会返回上一个函数中继续执行之前未执行的内容,依次向上类推

#include<stdio.h>
long fac(int n)
{
    if(n==1||n==0)
    {
        return 1;
    }
    else
    {
        t=n*fac(n-1);
        return t;
    }
}

void main()
{
    int res=0,n=0;
    scanf("%d",&n);
    res=fas(n);
    printf("结果是%d\n",res);
}

上述程序流程图:

image.png
fac(n)函数调用了4次,递归了3次

递归调用:调用完函数后要返回主函数位置,继续执行未执行的内容

编译预处理与条件编译

编译预处理

引入文件或者函数库:

  1. #include<文件名> //标准库函数头文件
  2. #include"文件名" //用户自定义头文件

条件编译

#ifndef 头文件名
#define 头文件名
   ………………
#endif

//此处的头文件名必须全大写,
//前后必须添加下划线,'.'也变为下划线

//例如 stdio.h 变为 _STDIO_H_

宏定义

形式:#define 宏名 宏体

//无参宏
#define M (5*x+x*x)
void main()
{
    int s,x;
    scanf("%d",&x);
    s=4*M+5*M+6*M;
    printf("s=%d\n",s);
    //当x=5时,s=750
}

//有参宏
#define M(y) 4*y+y*y
void main()
{
    int s,x=5;
    s=M(x);
    printf("s=%d\n",s);
    //当x=5时,s=45
    //M(x)被替换为4*x+x*x即(4x5+5x5)
}

变量存储类型

局部变量

局部变量:其又被称为内部变量,在大括号内被定义,则定义的值只在该大括号内有效

全局变量

全局变量:在大括号外被定义,从被定义开始到程序结束,均有效

静态变量 static

静态变量static:static 类型变量只创建一次,只赋初值一次,若static变量未赋值,则默认为0(无论static使用多少次,其都使用上次的值,而不是定义时的初始值)

static 数据类型 变量名

寄存器变量register

寄存器变量register: 当要频繁的使用某个变量时,可以将其定义为寄存器变量,以提高程序运行速度

register 数据类型 变量名

外部变量extern

外部变量extern:拓展变量作用域(有效范围),从extern定义变量处开始

extern 数据类型 变量名

结构体、共用体与枚举

结构体

结构体是一种自定义的数据类型,它可以由其他不同的数据类型共同来构成一个全新的数据类型

struct 结构体名称(可省略)
{
    数据类型 变量名;
    数据类型 变量名;
    …………………………
};

结构体中数据类型可相同,也可不同,不同结构体中的变量名可以相同,结构体定义在函数外面时,可以供其作用域内所有函数使用,结构体不会进行内存分配,只有在用结构体类型定义变量时,才会进行内存分配

先定义结构体类型,再定义结构体变量

struct student  //定义结构体
{
    char mum[10];
    char name[10];
    int  chinese;
    int  match;
};

该结构体在内存中存放的位置如图:
image.png

struct student stu,s[10];
//定义结构体变量stu和数组s

typedef struct student AB
//将结构体类型赋与一个全新的名字AB
AB stu,s[10];
//与上面定义等价

//变量stu的所占字节为结构体内所有成员
//所占字节之和(即10+10+4+4=28)


//结构体类型的变量可以在定义结构体类型
//时同时定义
struct student  //定义结构体
{
    char mum[10];
    char name[10];
    int  chinese;
    int  match;
}stu,s[10];

//若之前已经省略了结构体名,则在后面程序
//中将不能再定义新的该结构体的变量

结构体成员的引用:

结构体变量名.成员名称(普通变量名加".")

结构体类型指针->成员名称(指针用"->")

结构体类型变量 sum,*p
p=&sum;
(*p).成员名==p->成员名(两者等价)
//通过*p访问到sum,再用"."

结构体类型变量作为形参是单向值传递,结构体变量为指针时,是双向地址传递

结构体变量初始化:

变量名={数据1,数据2……} //{}内的数据按顺序依次赋值给成员,数据不全,则其余默认为0

struct student s[100];
strcpy(s[0].num,"20200001");
//给下标为0的结构体的成员num赋值

s[1].chinese=80;
//余下的成员变量赋值同理

(s+99)->match=90;
//等价于s[99].match=90;

共用体

union sample
{
    char ch;
    short s;
    float f;
} un;

该共用体在内存中存放的位置如图:
image.png

共用体成员共享内存空间,该类型变量内存所占字节数由占内存最多的成员决定,而且后面写入的数据会将前面写入的数据覆盖掉,即数据只有最后一次写入才是完整的

枚举

enum 枚举名
{
    枚举元素1,枚举元素2,……     
    //注意,各元素之间用逗号隔开
};                            
//注意,末尾有分号;

枚举在C语言中其实是一些符号常量集,直白点说:枚举定义了一些符号,这些符号的本质就是int类型的常量,每个符号和一个常量绑定,常量默认从0开始依次递增
宏定义类似,但在定义多个的时候更方便

#define MON  1
#define TUE   2
#define WED  3
#define THU   4
#define FRI    5
#define SAT   6
#define SUN   7

//上述代码等价于:
enum DAY
{
     MON=1, TUE, WED, THU, FRI, SAT, SUN
};

总结:宏定义先出现,用来解决符号常量的问题;后来人们发现有时候定义的符号常量彼此之间有关联(多选一的关系),用宏定义来做虽然可以但是不贴切,于是乎发明了枚举来解决这种情况

文件相关

文件类型与区别

二进制文件:以二进制数存放在计算机内,可以保存一切数据,如图片,音乐,电影等

文本文件:将文件转成ASCLL码存储,只能保存"文字"类型的数据,如小说,代码,文章

文件的打开与关闭

C语言提供一个已经定义好的结构体FILE,该结构体用于表示文件类型,表明对应变量是一个文件

文件名:

  • C:\音乐\鸿雁.mp3 绝对路径
  • 班级成绩表 相对路径,比绝对更快,但要保证文件在当前
{
…………………………
    FILE *指针变量名
    //所有文件的操作均离不开这个定义
    //的FILE结构体类型的指针
}
#include<stdio.h>
FILE *fp \\定义FILE类型的指针fp
fp=fopen("文件名",操作)
//fopen()打开文件的函数

fclose(fg);  //关闭文件

操作:

  • “r” 打开已有文本文件,只允许读数据,若文件不存在,则打开失败
  • "w"打开或创建文本文件,只允许写数据,若文件存在,则删除原文件数据再打开
  • "a"打开已有文件,并在文件末尾追写数据
  • “w+”,“r+”,"a+"均在原来的基础上添加对文本文件的可读可写
  • “wb”,“rb”,“ab”,“wb+”,“ab+”,"rb+"作用对象为二进制文件,效果与文本文件类似

文件的读写

格式化读写函数

格式化读写函数 fscanf(),fprintf()

注意:读操作指从文件中读取数据到内存中,写操作指将内存中的数据写入文件

写函数:fprintf(指向文件的指针,格式化输出,要写入的数据所在地址)

读函数:fscanf(指向文件的指针,格式化输出,要读出的数据所存的变量)

#include<stdio.h>
typedef struct student
{
    char No[20];
    char Name[20];
    int gradeC;
    int grademath;
}stu;
int main()
{
    FILE *fp;
    stu A={"20200001","xxx",85,80},B;
    if((fp=fopen("C:\\student.txt","w"))
    ==NULL)
    {
        return -1;
        //文件打开失败,退出程序
    }
    fprintf(fp,"%s %s %d %d\n",
    A.No,A.Name,A.gradeC,A.grademath)
    
    fclose(fp); //关闭文件
    
    if((fp=fopen("C:\\student.txt","r"))
    ==NULL)  //绝对路径
    {
        return -1;
    }
    fscanf(fp,"%s %s %d %d\n",
    B.No,B.Name,B.gradeC,B.grademath);
    //将fg所指文件中的内容读出,并赋给结构体B
    
    fclose(fp); //关闭文件
    
    return 0;
}

若要数据写入文件后立即读出数据,则将"w",“r"换为"w+”,只用一个if从句就可以达到效果

字符读写函数

字符读写函数 fgetc(),fputc()

fgetc():从指定文件中读出一个字符,读出成功则返回读取到的字符,读取失败则返回EOF(-1)

fputc(): 从指定位置写入一个字符到文件中,写入成功返回写入的字符,写入失败,则返回EOF(-1)

ch=fgetc(FILE *fp);
//从文件指针fp中读取一个字符数据到变量ch中

fputc(int ch,FILE *fp);
//将变量ch的值写入指针fp所指文件

字符串读写函数

字符串读写函数 fgets(),fputs()

fgets(char *ch,int max,FILE *fp);
//从文件指针fp所指文件中读出最多max-1个
//数据放入*ch所指地址中,剩下一个
//存储结束符0(系统自动添加)

fputs(char *st,FILE *fp);
//将*st所指的字符串(st即首地址)写入目标文件
//中,写入成功返回0,不成功,则返回非0

feof(FILE *fp);
//若文件未结束,feof(fp)==假,否则feof(fp)
//为真

二进制数据块读写函数

二进制数据块读写函数 fread(),fwrite()

fwrite(stu,sizeof(stu),3,fp);
//stu 从该位置(一般是数组)读出数据
//sizeof(stu)  每次写入的数据的字节长度
//3 一次性写几个数据块
//fp 写入的目标文件

fread(&stu[0],sizeof(stu),1,fp)
//stu 将数据写入到的内存首地址
//sizeof(stu)  每次读出的数据的字节长度
//3 一次性读几个数据块
//fp 数据读取的文件

文件位置下标

rewind(fp);  
//位置回到文件下标起点,即fpos=0

fseek(fp,0,SEEK_END);
//在*fp所指文件中将fpos指向相对于文件结尾偏移0字节的位置
//若偏移量为负,则是将fpos向前移动

//SEEK_END==2  fpos指向文件结尾
//SEEK_CUR==1  fpos当前所在位置
//SEEK_SET==0  fpos指向文件开头

无论是读取文件数据还是写入文件数据,文件位置下标fpos 都要自动向后移动到新的位置,以便读写操作,这跟人在纸上写字是一个道理

动态分配函数 malloc

引入头文件<malloc.h>

malloc()函数作用:在堆上分配一片独立空间

(int*)malloc(N*sizeof(int)) 
//此函数会自动将其空间的地址返回
//N*sizeof(int) 为要分配的空间大小

free(a);  //释放空间a

//realloc()函数:在堆上重新分配空间
(int*)realloc(p,N*sizeof(int))   
//p 指向原来的空间所在的地址
//N*sizeof(int) 扩展的空间大小

//calloc函数:在堆上存放数组
(int*)calloc(5,sizeof(int))
// 5 要存储的数组长度
// sizeof(int) 数组每个元素的大小(字长)
  • 16
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

freejackman

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值