当前位置:   article > 正文

(超详细)C语言总结 嵌入式C基础学习分享_c语言学习文档

c语言学习文档

目录

一、数据类型、常量、变量及运算符

1.数据类型

基本数据类型(一个字节8bit)

2.变量类型的转换

3.常量

4.变量

5.运算符

5.内存

二、输入输出专题

1.putchar:字符输出函数

2.printf:格式输出函数

3.getchar:字符输入函数

4.scanf:格式输入函数

5.gets:字符串输入函数

三、控制语句

1.if语句

2.Switch语句

3.while与do while

4.for语句

四、数组

1.一维数组

2.二维数组

五、字符串操作

1.strlen

2.strcpy

3.strcat

4.strcmp

六、函数:

1.函数定义

2.函数声明

3.函数调用

4.函数传参

七、指针

1.一级指针

2.二级指针

1.含义

2.定义

指针的类型

指针所指向的类型

总结


一、数据类型、常量、变量及运算符

1.数据类型

基本数据类型(一个字节8bit)

(1)bool类型:只有两个量true和false,表示逻辑真值和逻辑假值。

(2)char类型:字符型,占1 个字节。在给字符型变量赋值时,需要用一对英文半角格式的单引号(' ')把字符括起来。字符变量实际上并不是把该字符本身放到变量的内存单元中去,而是将该字符对应的 ASCII 编码放到变量的存储单元中。
数值表示范围是:

有符号(signed char):-2^(8-1) – 2(8-1) -1 (即 -128 ~ 127)

 无符号(unsigned char): 0 ~ 2^8 -1 (即 0~255)

(3)整型

int:数据类型大小是4字节, - 2^31 ~ + 2^31-1

unsigned int :无符号整型 , 0- (2^32 -1)

short:短整型,数据类型大小是2字节,

signed short: - 2^15 ~ + 2^15-1

unsigned short  :无符号短整型 , 0- (2^16 -1)  65535

(4)浮点型:用于存储小数,精度更高

float :单精度浮点型,存储4字节 ,打印格式为%f 。
double :双精度浮点型,存储8字节,打印格式为%lf 。

         通过上图可以发现两种数据类型的输出结果都是相同的,因为系统会默认输出小数点的后6位小数。他们的区别就在于float的数据类型有效位是小数点后面的6~7位,而double的有效位是小数点后面15~16位。

2.变量类型的转换

(1)隐式类型转换: 由编译器自动完成了类型的转换  
   转换规则 :将精度低的向精度高的转换, 将范围小的往范围大的转换 、有符号数 往 无符号转换 

如上图,计算表达式中 a,b都为int型,但s为double型,所以运行结果就会自动转换为精度更高的double型。

(2)强制类型转换:   (目标类型)原类型变量手动的将一个类型转换为另一个类型 ,当转换的 精度不匹配时, 会存在数据 精度丢失的问题 
    显式的数据类型转换实现的一般形式为:(数据类型名称)< 表达式 > ,实例如下:

 上图中,定义的总分和科目数都是int型,如不进行强制类型转换就会丢弃小数部分。

3.常量

(1)整型常量:即整数

整数可以是十进制数、八进制数和十六进制数。

(2)浮点常量:又称为实数,一般含有小数部分。在C语言中,实数只有十进制,分为数值常量和指数常量。

数值常量:
        例如:PI  3.14       G  9.8     2.7
指数常量: 3.5789e-8  表示 3.5789 * 10 ^-8 等价于 0.000000035789

(3)字符常量:char   'A'  'z'  '0'  其本质是  对应字符的 编码值 ASCII  

(4)字符串常量:指用双引号括起来的一串字符表示的数据,如 "A" "abc"  "012jklk" "hello!", 由多个字符,连续存放在内存中, 且有一个结束符'\0' 即值 =0

(5)标识常量:宏定义   类似于字符串替换 。形式为:#define <标识常量名称>  <常量> ,如下:
    #define  PI  3.14
    #define  G   9.8

4.变量

 变量说明的一般形式是:

<存储类型>    <数据类型 >    <变量名> ;

<存储类型>是关键词auto、register、static和extern

<数据类型>可以是基本数据类型,也可以是自定义的数据类型

(1)auto:auto说明的变量只能在某个程序范围内使用,通常在函数体内或函数中的复合语句里。(默认是随机值) 在函数体的某程序段内说明auto存储类型的变量时可以省略关键字auto,如下:    auto int  k ;        int  j ;             double x;      

(2)register:register称为寄存器型,register变量是想将变量放入CPU的寄存器中,这样可以加快程序的运行速度。 如申请不到就使用一般内存,同auto ;

        注:不能用“&”来获取register变量的地址。

(3)static:static变量称为静态存储类型的变量,既可以在函数体内,也可在函数体外说明。(默认是0)

面试题: 请描述 static的 所有用法?

被static修饰的变量只能初始化一次,如果没有初始化,整型默认为零(字符型为空)

1) 修饰局部变量 ,扩大生命周期到程序整个运行周期。存储方式由动态区到静态区。在内存中以固定地址存放的,而不是以堆栈方式存放,只要程序没结束,就不会随着说明它的程序段的结束而消失,它下次再调用该函数,该存储类型的变量不再重新说明,而且还保留上次调用存入的数值。

2) 修饰全局变量 ,只有在本文件中有效,就算加了extren外部声明也没有用

3) 修饰函数   static int func(); sratic修饰时不能被其它文件调用 

(4)extern:当变量在一个文件中的函数体外说明,所有其他文件中的函数或程序段都可引用这个变量。表示不需要给该变量分配存储空间 ,在其他文件中 已经被定义了 ,该文件 只是引用 该变量 。如下图:

(5)const:常量类型  ,指定变量的存储空间位于常量区仅在修饰全局变量时 ,若 const 修饰局部变量  其存储空间位置不会改变仅表示该变量只读 。

(6)sizeof:可以用于计算 类型或 变量消耗的 存储空间 单位字节

 示例:sizeof(int)     sizeof(变量名)

5.运算符

(1)关系运算符

(2)逻辑运算符

·逻辑非:1==>0,0==>1

·逻辑与:全1为1

·逻辑或:有1为1

(3)位运算符

·位逻辑反:a=~b,若b=1 0 1 ,则a=0 1 0

·位逻辑与:同1才为1

·位逻辑或:有1就为1

·位逻辑异或:有1为1,同1为0

·左移:若x=00110,b=x<<1,则b=01100

·右移 :若x=00110,b=x>>1,则b=00011

(4)赋值运算符

赋值运算符为“=”,其运算的一般形式如下: <左值表达式> = <右值表达式>

eg:a  =+ b  ===>  a = a + b( =   +=  -=  *=   /=同上)

(5)三目运算符

 表达式1  ?  表达式2 : 表达式3 
 先进行表达式1的判断,为true执行表达式2,否则执行表达式3。

  1. #include<stdio.h>
  2. int main()
  3. {
  4. int a,b;
  5. printf("please input a:");
  6. scanf("%d",&a);
  7. a>5?b=1:0;//等同于if(a>5) b=1;else b=0;
  8. printf("%d\n",b);
  9. return 0;
  10. }

执行结果如下:

 (6)sizeof运算符

运算的一般形式:sizeof(<类型或变量名>)      注意:它只针对数据类型,而不针对变量!     

 例如:     sizeof(double)     sizeof(long) 

(7)C运算符的优先级

5.内存

以下是针对linux系统,所以有内核区。

二、输入输出专题

1.putchar:字符输出函数

格式: putchar( c ) ,c为字符常量、变量或表达式

功能:把字符c输出到显示器上

2.printf:格式输出函数

格式:printf(“格式控制串”,输出表)

功能:按指定格式向显示器输出数据

3.getchar:字符输入函数

字符输入函数getchar 格式:  getchar( )

功能:从键盘读一字符

4.scanf:格式输入函数

格式: scanf(“格式控制串”,地址表)

功能:按指定格式从键盘读入数据,存入地址表指定

5.gets:字符串输入函数

从键盘输入一以回车结束的字符串放入字符数组中,并自动加‘\0’

  1. #include<stdio.h>
  2. int main( )
  3. { char s[15];
  4. printf("Input a string:");
  5. gets(s);
  6. printf("%s\n", s);
  7. return 0;
  8. }

注:

1:输入串长度应小于字符数组维数

2:与scanf函数不同,gets函数并不以空格作为字符串输入结束的标志。

运行结果如下图:

三、控制语句

1.if语句

一般格式:if (表达式)     

                               语句块1      

                else

                             语句块2

 当if语句后只有语句话时,大括号可省略。

阶梯形式:if(表达式1) 语句块1   

                         else if(表达式2) 语句块2      

                           else if(表达式3) 语句块3         

                               else if(表达式4) 语句块4                                 

                           ...    else 语句块n

  1. #include<stdio.h>
  2. int main( )
  3. {
  4. int a;
  5. printf("please input a(0-100):");
  6. scanf("%d",&a);
  7. if(a>=90)
  8. printf("a");
  9. else if(a>=80)
  10. printf("b");
  11. else if(a>=70)
  12. printf("c");
  13. else if(a>=60)
  14. printf("d");
  15. else
  16. printf("!");
  17. return 0;
  18. }

嵌套形式:一个if的 语句块中 有另一if语句
if( 条件表达式1  )
{
    代码块1;;
    if(条件表达式2){ 代码块3 ;; } else {代码块4 ;;}
    代码块5;;

else
{
    代码块6;;
    if(条件表达式3){ 代码块7 ;; } else {代码块8 ;;}
    代码块9;;
}

  1. #include<stdio.h>
  2. int main( )
  3. {
  4. int a;
  5. printf("please input a(0-100):");
  6. scanf("%d",&a);
  7. if(a>= 80)
  8. {
  9. if(a >= 90) printf("a");
  10. else printf("b");
  11. }
  12. else
  13. {
  14. if(a>= 60) printf("c");
  15. else printf("d");
  16. }
  17. return 0;
  18. }

2.switch语句

格式:switch( 整型表达式 )
            {
                case 常量1: 语句块1;;  break;
                case 常量2: 语句块2;;  break;
                case 常量3: 语句块3;;  break;
                .....
                default: 语句块n;;   
            }

continue是直结束本次循环,而break是终止本层循环

  1. #include<stdio.h>
  2. int main( )
  3. {
  4. int a;
  5. printf("please input a(0-100):");
  6. scanf("%d",&a);
  7. int n=a/10;
  8. switch(n)
  9. {
  10. case 10:printf("s");break;
  11. case 9:printf("a");break;
  12. case 8:printf("b");break;
  13. case 7:printf("c");break;
  14. case 6:printf("d");break;
  15. default:printf("!");
  16. }
  17. return 0;
  18. }

3.while与do while

(1)while

                基本形式: while (表达式)

                                         {     语句块; }

  1. #include<stdio.h> //1+2+3...+100
  2. int main()
  3. {
  4. int i=0,s=0;
  5. while(i<=100)
  6. {
  7. s+=i;
  8. i++;
  9. }
  10. printf("%d ",s);
  11. return 0;
  12. }

(2)do while

                基本格式:do

                        {  }while(表达式);

  1. #include<stdio.h>
  2. int main()
  3. {
  4. int i=0,s=0;
  5. do
  6. {
  7. s+=i;
  8. i++;
  9. }while(i<=100);
  10. printf("%d ",s);
  11. return 0;
  12. }

4.for语句

结构:
    for( 表达式1 ; 表达式2  ; 表达式3 )
    {
        循环体;;
    }
    
    运行逻辑: 
    (1) 执行一次 表达式1, 完成初始化
    (2) 判断表达式2 真 还是 假 
        若真 
            (3)执行 循环体 
            (4)执行 表达式3
            (5) 回到 动作(2) 继续执行 
        若假 
            退出 for循环结构

  1. 九九乘法表
  2. #include<stdio.h>
  3. int main()
  4. {
  5. int i,j;
  6. for(i=1;i<=9;i++)
  7. {
  8. for(j=1;j<=i;j++)
  9. {
  10. printf("%d*%d=%d\t",i,j,i*j);
  11. }
  12. printf("\n");
  13. }
  14. return 0;
  15. }

四、数组

1.一维数组

(1)定义:一维数组是指只有一个下标的数组。它在计算机的内存中是连续存储的。 C语言中,      一维数组的说明一般形式如下: <存储类型>  <数据类型 >  <数组名>[<表达式>] ;

例:int arr[10];  int a[3];     数组元素表示形式:数组名[下标]

(2)初始化:在定义数组时(数组必须先定义后使用),为数组元素赋初值 int arr[3]={1,2,3};

        等价于arr[0]=1.arr[1]=2,arr[2]=3 。数组不作越界检查,所以定义时如int arr[2]={1,2,3,4,5,6}越界为错。

  1. 冒泡排序
  2. #include<stdio.h>
  3. int main()
  4. {
  5. int n[5];
  6. int i, j, temp;
  7. printf("请输入需要排序的5个数\n");
  8. for(i=0;i<5;i++)
  9. {
  10. scanf("%d",&n[i]);
  11. }
  12. for (i = 0; i <= 5-1; i++)
  13. {
  14. for (j = 0; j <= 5-i-1; j++)
  15. {
  16. if (n[j] > n[j + 1])
  17. {
  18. temp = n[j];
  19. n[j] = n[j + 1];
  20. n[j + 1] = temp;
  21. }
  22. }
  23. }
  24. printf("排序过后的数顺序:\n");
  25. for (i = 0; i < 5; i++)
  26. printf("%-2d", n[i]);
  27. printf("\n");
  28. return 0;
  29. }

2.二维数组

(1)定义:数据类型   数组名[常量表达式][常量表达式];

声明时列数不能省略,行数可以               

元素个数=行数*列数

例:int arr[5][5];        float b[2][1];

(2)初始化:二维数组元素的初始化 分行初始化 按元素排列顺序初始化

形式:数组名[下标][下标]   

 例:int a[][3]={{1},{4,5}};

 二维数组的运用如下列一个简单的五子棋:

  1. //五子棋
  2. #include<stdio.h>
  3. char qipan[16][16];
  4. int x,y;
  5. void initQipan()
  6. {
  7. int i,j;
  8. for(i = 0;i < 16 ;i++)
  9. for(j = 0;j<16 ;j++)
  10. qipan[i][j] = '*';
  11. }
  12. void printQipan()
  13. {
  14. int i,j;
  15. for(i = 0;i < 16 ;i++)
  16. {
  17. for(j = 0;j<16 ;j++)
  18. printf("%c ",qipan[i][j]);
  19. printf("\n");
  20. }
  21. }
  22. void zuobiao()
  23. {
  24. while(1)
  25. {
  26. printf("请白方落子,输入坐标:");
  27. scanf("%d%d",&x,&y);
  28. qipan[x][y]='#';
  29. printQipan();
  30. printf("请黑方落子,输入坐标:");
  31. scanf("%d%d",&x,&y);
  32. qipan[x][y]='@';
  33. printQipan();
  34. }
  35. }
  36. int main()
  37. {
  38. printf(" \n");
  39. printf("----------五子棋游戏-------------\n");
  40. printf(" \n");
  41. initQipan();
  42. printQipan();
  43. zuobiao();
  44. return 0;
  45. }

五、字符串操作

1.strlen

格式:strlen(字符数组)

功能:计算字符串长度

返值:返回字符串实际长度,不包括‘\0’在内

  1. #include<stdio.h>
  2. #include<string.h>
  3. int main()
  4. {
  5. char s[]="hello";
  6. int n=strlen(s);
  7. printf("%d",n);
  8. return 0;
  9. }

2.strcpy

格式:strcpy(字符数组1,字符串2)

功能:将字符串2,拷贝到字符数组1中去

返值:返回字符数组1的首地址

说明: 1.字符数组1必须足够大

            2.拷贝时‘\0’一同拷贝

  1. #include <stdio.h>
  2. #include <string.h>
  3. int main()
  4. {
  5. char a[]="123";
  6. char d[] = "nihao world";
  7. strcpy(a, d);
  8. printf("%s\n", a);
  9. return 0;
  10. }

3.strcat

格式:strcat(字符数组1,字符数组2)

功能:把字符数组2连到字符数组1后面

返值:返回字符数组1的首地址

说明:1.字符数组1必须足够大     

           2.连接前,两串均以‘\0’结束;连接后,串1的‘\0’取消,新串最后加‘\0’

  1. #include <string.h>
  2. #include <stdio.h>
  3. int main()
  4. {
  5. char a[]="123";
  6. char c[]= "hello";
  7. strcat(a, c);
  8. printf("%s\n", a);
  9. return 0;
  10. }

4.strcmp

格式:strcmp(字符串1,字符串2)

功能:比较两个字符串 比较规则:对两串从左向右逐个字符比较 ASCII码),直到遇到不同字符或‘\0’为止                                          

返 值:返回int型整数

  1. #include <stdio.h>
  2. #include <string.h>
  3. int main()
  4. {
  5. char a[]="123";
  6. char c[]= "hello";
  7. strcmp(a, c);
  8. if(a>c)
  9. printf("1");
  10. else
  11. printf("2");
  12. return 0;
  13. }

六、函数:

1.函数定义

返回值类型  函数名 (形参列表) {  函数体 }

例:int sum(){  };    void work(){ };

2.函数声明

返回值类型  函数名 (形参列表);  // 函数原型

函数5要素:

(1)功能明确

(2)函数原型

(3) 参数 作用 传参方式

(4)返回值

(5)注意事项  bug 部分

3.函数调用

函数名(实参列表);  

 例: sum();

4.函数传参

值传递:  实参复制其值赋值给形参  ,函数中操作的是形参

地址传递:  将实参的地址赋值给形参(指针类型)  ,函数可以通过这个指针操作实参

1)指针函数 :   指针函数是指一个函数的返回值为地址量的函数

一般形式:

        <数据类型>  *  <函数名称>(<参数说明>) { 语句序列;}

例如:

  1. #include<stdio.h>
  2. int func(int *p,int *q)//如果用return 只能返回一个值(return a 或return b),所以定义两个指针去接收
  3. {
  4. int a=1;
  5. int b=2;
  6. *p=a;
  7. *q=b;
  8. return 0;
  9. }
  10. int main()
  11. {
  12. int x,y;
  13. func(&x,&y);
  14. printf("%d %d\n",x,y);
  15. return 0;
  16. }

2)函数指针

函数指针: 是一个指针变量指向一个函数的入口地址

一般形式: <数据类型> (*<函数指针名称>)(<参数说明列表>);

函数类型:

int func(int *a,int *b);扣掉所有的变量剩下的就位类型, 其类型为  int (int *,int *);

如何定义函数指针 : int (*p) (int *,int *);

int arr[3];==>int (*p)[3] =&arr;==>int *p = arr;

函数名:  

1) 代指这个函数   

2) 代指这个函数 的 首地址(函数入口地址)

函数指针的使用:

通过该指针调用这个函数  除此外,其他指针操作均不能使用

1) (*函数指针)(参数表)

2) 函数指针(参数表)

typedef 关键字:  给类型取别名

结构:  typedef  原类型名   类型别名;  

typedef 与 宏定义的区别: 
    1) typedef 在编译阶段 处理  有语法检查,有类型判定 
    2) define 宏  在预处理阶段处理  其本质就是字符串替换, 不会有任何的语法或类型检查

七、指针

1.一级指针

(1)地址和变量

地址:在计算机内存中,每一个字节单元,都有一个编号,称为地址。

变量:在C语言中,内存单元的地址称为指针,专门用来存放地址的变量,称为指针变量

(2)一般形式

存储类型   数据类型  变量名;

auto        int       a =5 ;

auto int *    p=&a; // 指针的定义与初始化

含义: 定义了一个指针变量p, 该变量将会存储一个地址,该地址所在的内存(就像房间号) 是 int类型

野指针: 定义时 没有给定初始值,或指向的内存地址不可用

空指针: 指针变量的值 是 地址0 即 NULL  (void*)0

(3)指针的不同意义

*指针取值运算符

*指针变量  : 表示取出指针变量指向的内存中的值

示例 int *p = &a;  ==> *p 等同于 a

设p为一个指针,则:

p — 指针变量, 它的内容是地址量

*p — 指针所指向的对象, 它的内容是数据

&p — 指针变量占用的存储区域的地址,是个常量

(4)指针运算

 指针相减:运算的结果是两指针指向的地址位置之间相隔数据的个数,不是两指针持有的地址值相减的结果。

2.二级指针

1.含义

指 一个指针指向了 另一指针  该指针中存放的是 另一个指针的地址

2.定义

int a;

int *p = &a;

int **pp = &p;  二级指针定义

指针数组:  即一个数组 中存放的元素 是指针类型  这个数组即指针数组,例:int *arr[5];

  1. int p; 这是一个普通的整型变量
  2. int *p; 首先从P处开始,先与*结合,所以说明P是一个指针,然后再与int结合,说明指针所指向的内容的类型为int型。所以P是一个返回整型数据的指针。
  3. int p[3]; 首先从P处开始,先与[]结合,说明P是一个数组,然后与int结合,说明数组里的元素是整型的,所以P 是一个由整型数据组成的数组。
  4. int *p[3]; 首先从P处开始,先与[]结合,因为其优先级比*高,所以P是一个数组,然后再与*结合,说明数组里的元素是指针类型,然后再与int结合,说明指针所指向的内容的类型是整型的,所以P是一个由返回整型数据的指针所组成的数组。
  5. int (*p)[3]; 首先从P 处开始,先与*结合,说明P 是一个指针然后再与[]结合(与"()"这步可以忽略,只是为了改变优先级),说明指针所指向的内容是一个数组,然后再与int 结合,说明数组里的元素是整型的.所以P是一个指向由整型数据组成的数组的指针。
  6. int **p; 首先从P 开始,先与*结合,说是P 是一个指针,然后再与*结合,说明指针所指向的元素是指针,然后再与int 结合,说明该指针所指向的元素是整型数据.由于二级指针以及更高级的指针极少用在复杂的类型中,所以后面更复杂的类型我们就不考虑多级指针了,最多只考虑一级指针。
  7. int p(int); 从P 处起,先与()结合,说明P 是一个函数,然后进入()里分析,说明该函数有一个整型变量的参数,然后再与外面的int 结合,说明函数的返回值是一个整型数据。
  8. int (*p)(int); 从P 处开始,先与指针结合,说明P 是一个指针,然后与()结合,说明指针指向的是一个函数,然后再与()里的int 结合,说明函数有一个int 型的参数,再与最外层的int 结合,说明函数的返回类型是整型,所以P 是一个指向有一个整型参数且返回类型为整型的函数的指针。
  9. int *(*p(int))[3]; 从P 开始,先与()结合,说明P 是一个函数,然后进入()里面,与int 结合,说明函数有一个整型变量参数,然后再与外面的*结合,说明函数返回的是一个指针,,然后到最外面一层,先与[]结合,说明返回的指针指向的是一个数组,然后再与*结合,说明数组里的元素是指针,然后再与int 结合,说明指针指向的内容是整型数据.所以P 是一个参数为一个整数据且返回一个指向由整型指针变量组成的数组的指针变量的函数。

指针的类型

把指针声明语句里的指针名字去掉,剩下的部分就是这个指针的类型。这是指针本身所具有的类型。

(1)int*p;//指针的类型是int*

(2)char*p;//指针的类型是char*

(3)int**p;//指针的类型是int**

(4)int(*p)[3];//指针的类型是int(*)[3]

(5)int*(*p)[4];//指针的类型是int*(*)[4]

指针所指向的类型

把指针声明语句中的指针名字和名字左边的指针声明符*去掉,剩下的就是指针所指向的类型。

  (1)int*p; //指针所指向的类型是int

(2)char*p; //指针所指向的的类型是char

(3)int**p; //指针所指向的的类型是int*

(4)int(*p)[3]; //指针所指向的的类型是int()[3]

(5)int*(*p)[4]; //指针所指向的的类型是int*()[4]


总结

写到这里,C语言基础内容就差不多完成了,不太全面的知识点后续还会进行优化补充,希望对大家有用。后续会根据情况逐一更新数据结构、文件IO、网络编程以及ARM等等内容。和大家一起分享、学习。如有错误,请大家指出。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/789669
推荐阅读
相关标签
  

闽ICP备14008679号