C语言基础(有基础)

1 篇文章 0 订阅

linux下的

是一种通用的、面向过程式的计算机编程语言

#include <stdio.h>        //#include 预处理命令,用来引用头文件, stdio.h 头文件 
int main()               //开始
{
    /* 一个注释 */
    printf("Hello, World! \n");
    return 0;           //返回
}
  • 安装到vm中
  1. 链接Xshell

  2. 安装gcc

  3. 测试

  4. 运行源码文件在linux中运行

    $ gcc test1.c test2.c -o main.out   //多个
    $ ./main.out
    $ gcc hello.c     //单个.c文件
    

基本语法

  • C的令牌(Token) 关键字、标识符、常量、字符串值,或者是一个符号

  • 分号结尾

  • 注释 // /* */

  • 标识符

  • 关键字

数据类型

基本类型
  1. 整数类型

在这里插入图片描述

  1. 浮点(1字节=8bit)
    在这里插入图片描述
枚举类型

算术类型,定义在程序中只能赋予一定的离散整数值的变量

void类型

没有可用的值。

  1. 函数返回为空 void exit (int status);
  2. 函数参数为空 int rand(void);
  3. 指针指向void void *malloc( size_t size )
派生类型

指针、数组、结构、共用体、函数

变量

定义 type variable ; type variable=value;

变量声明
  1. int a 声明,也是定义 需要建立存储空间
  2. extern int a 声明,不是定义 不需要建立存储空间,通过extern声明变量名而不定义它
左值/右值
  1. 左值lvalue :可以出现在赋值号 左边或右边 int a=0;
  2. 右值rvalue :术语右值,存储在内存中某些地址的数值。只能出现在右边 10=20(报错)

常量

0 八进制

0x 十六进制

后缀U 无符号

后缀L 长整数

浮点常量 整数部分、小数点、小数部分和指数部分组成:使用小数形式表示时,必须包含整数部分、小数部分,或同时包含两者。当使用指数形式表示时, 必须包含小数点、指数,或同时包含两者。带符号的指数是用 e 或 E 引入的

定义常量
  1. #definde 预处理器 #define LENGTH 10 //之后LENGTH的值为定值10
  2. const int var = 5; //不可以缺项之后LENGTH的值在函数内为定值10

存储类

  • auto 默认存储类 修饰局部变量
  • register 存储类 在寄存器中不是在RAM的局部变量,(一个寄存器大小)
  • static 存储类
    1. 在函数调用之间保持局部变量的值,每次调用该函数时,只初始化一次
    2. 用于全局变量,作用域在声明它的文件内
static int a=10;//a是全局变量可直接调用
int main(){
   while(a--){
    fun();}
    return 0;
}
void fun(void){
    static int b=5;//局部变量,值初始化一次为5,后面不会再重置
    b++;
    print("%d,%d",a,b);//%输出""内的内容,
}
9,6
8,7
7,8
    .....
  • extern 存储类 全局变量,对所有程序文件都可见,
    1. 对于无法初始化的变量,会把变量名指向一个之前定义过的存储位置。
    2. extern 是用来在另一个文件中声明一个全局变量或函数。

在这里插入图片描述

输出 count is 5

运算符

  • 逻辑运算符

  • 在这里插入图片描述

  • 位运算符

在这里插入图片描述

  • 杂项

在这里插入图片描述

判断

  • if else

  • switch

    switch(expression){
        case constant-expression  :
           statement(s);
           break; /* 可选的 */
        case constant-expression  :
           statement(s);
           break; /* 可选的 */
      
        /* 您可以有任意数量的 case 语句 */
        default : /* 可选的 */
           statement(s);
    }
    
  • A ? B : C //A真为B A假为C

循环

  • while
  • for
  • do while
  • break //跳出循环
  • continue //告诉一个循环体立刻停止本次循环迭代,重新开始下次循环迭代。
  • goto //将控制转移到被标记的语句。 少用

函数

  • 必有一个main()函数
  • 定义一个函数 return_type function_name( parameter list );
    • 例:int max(int num1, int num2);

作用域

  1. 在函数或块内部的局部变量 局部和全局同名时用局部保存在
  2. 在所有函数外部的全局变量 保存在静态存储单元
  3. 形式参数的函数参数定义中

数组

type arrayName [ arraySize ];//   int a[10];//10个int型数字
  • 赋值 类似java

enum(枚举)

enum 枚举名 {枚举元素1,枚举元素2,……};//
  • enum DAY
    {
          MON=1, TUE, WED, THU, FRI, SAT, SUN
    };
    //第一个默认为整型0,但此赋值为1,后面依次加一 即 TUE=2...
    
定义方式

可以与for一起用

  1. 先定义枚举类型,再定义枚举变量
enum DAY
{
      MON=1, TUE, WED, THU, FRI, SAT, SUN
};//可以在函数内也可以在外

enum DAY day;//在函数内
  1. 定义枚举类型同时定义枚举变量
enum DAY
{
      MON=1, TUE, WED, THU, FRI, SAT, SUN
} day;
  1. 省略枚举名称,直接定义枚举变量
enum
{
      MON=1, TUE, WED, THU, FRI, SAT, SUN
} day;
  1. 转换方式

    enum day weekend;
    weekend = ( enum day ) a;  //类型转换
    

指针

type *var_name;
int *p;//定义指针变量

定义一个变量 var=10(会分配一个地址)

定义一个指针 p

指针访问var的地址,于是p指向了变量的地址(&访问地址符号)

在这里插入图片描述

  • 指针常用操作
    1. 定义一个指针变量
    2. 把变量地址赋值给指针
    3. 访问指针变量中可用地址的值
int main ()
{
   int  var = 20;   /* 实际变量的声明 */
   int  *ip;        /* 指针变量的声明 */
 
   ip = &var;  /* 在指针变量中存储 var 的地址 */
 
   printf("var 变量的地址: %p\n", &var  );//var的分配地址
 
   /* 在指针变量中存储的地址 */
   printf("ip 变量存储的地址: %p\n", ip );//var的分配地址
 
   /* 使用指针访问值 */
   printf("*ip 变量的值: %d\n", *ip );//var的值 20
 
   return 0;
}
  • 在变量声明时,没有确切的地址,可以给指针赋值null
  • 菜鸟教程
概念描述
指针的算术运算可以对指针进行四种算术运算:++、–、+、-
指针数组可以定义用来存储指针的数组。
指向指针的指针C 允许指向指针的指针。
传递指针给函数通过引用或地址传递参数,使传递的参数在调用函数中被改变。
从函数返回指针C 允许函数返回指针到局部变量、静态变量和动态内存分配。
指针的算术运算
#include <stdio.h>
 
const int MAX = 3;
 
int main ()
{
   int  var[] = {10, 100, 200};
   int  i, *ptr;
 
   /* 指针中的数组地址 */
   ptr = var;
   for ( i = 0; i < MAX; i++)
   {
 
      printf("存储地址:var[%d] = %p\n", i, ptr );
      printf("存储值:var[%d] = %d\n", i, *ptr );
 
      /* 指向下一个位置 */
      ptr++;
   }
   return 0;
}
存储地址:var[0] = e4a298cc
存储值:var[0] = 10
存储地址:var[1] = e4a298d0          //int   4位所以+4
存储值:var[1] = 100
存储地址:var[2] = e4a298d4
存储值:var[2] = 200
指针数组
int  var[] = {10, 100, 200};
int *ptr[MAX];
ptr[i] = &var[i]; /* 赋值为整数的地址 */
printf("var[%d] = %d\n", i, *ptr[i] );//*ptr[i]==*&var[i]==var[i]
var[0]=10
var[1]=100
var[2]=200
指向指针的指针
int **var;

在这里插入图片描述

在这里插入图片描述

#include <stdio.h>
 
int main ()
{
   int  V;
   int  *Pt1;
   int  **Pt2;
   V = 100;
   /* 获取 V 的地址 */
   Pt1 = &V;
   /* 使用运算符 & 获取 Pt1 的地址 */
   Pt2 = &Pt1;
   /* 使用 pptr 获取值 */
   printf("var = %d\n", V );      //V的值
   printf("Pt1 = %p\n", Pt1 );    //V的地址
   printf("*Pt1 = %d\n", *Pt1 );  //pt1指针指向的值
    printf("Pt2 = %p\n", Pt2 );   //指针pt1的地址
   printf("**Pt2 = %d\n", **Pt2); //pt2指向pt1的指针  pt1指针指向的值
 
   return 0;
}
var = 100
Pt1 = 0x7ffee2d5e8d8
*Pt1 = 100
Pt2 = 0x7ffee2d5e8d0     //一个int型值4位 + 一个int型指针 4位
**Pt2 = 100
传递指针给函数

C 传递指针给函数 | 菜鸟教程 (runoob.com)

从函数返回指针

C 从函数返回指针 | 菜鸟教程 (runoob.com)

函数指针

typedef int (*fun_ptr)(int,int); // 声明一个指向同样参数、返回值的函数指针类型

一个指向函数的指针

#include <stdio.h>
 
int max(int x, int y)
{
    return x > y ? x : y;
}
 
int main(void)
{
    /* p 是函数指针 */
    int (* p)(int, int) = & max; // &可以省略   p指向max这个函数存储的位置
    int a, b, c, d;
    printf("请输入三个数字:");
    scanf("%d %d %d", & a, & b, & c);
    d = p(p(a, b), c); // /* 与直接调用函数等价,d = max(max(a, b), c) */
    printf("最大的数字是: %d\n", d);
    return 0;
}
回调函数

函数指针变量可以作为某个函数的参数来使用的,回调函数就是一个通过函数指针调用的函数。

简单讲:回调函数是由别人的函数执行时调用你实现的函数。

#include <stdlib.h>  
#include <stdio.h>
 
void populate_array(int *array, size_t arraySize, int (*getNextValue)(void))
{
    for (size_t i=0; i<arraySize; i++)
        array[i] = getNextValue();
}
 
// 获取随机值
int getNextRandomValue(void)
{
    return rand();
}
 
int main(void)
{
    int myarray[10];
    /* getNextRandomValue 不能加括号,否则无法编译,因为加上括号之后相当于传入此参数时传入了 int , 而不是函数指针*/
    populate_array(myarray, 10, getNextRandomValue);//此处getNextRandomValue作为int (*getNextValue)(void)形式的参数
    for(int i = 0; i < 10; i++) {
        printf("%d ", myarray[i]);
    }
    printf("\n");
    return 0;
}

字符串

在 C 语言中,字符串实际上是使用空字符 \0 结尾的一维字符数组。因此,\0 是用于标记字符串的结束。
在这里插入图片描述

结构体

一种用户自定义的可用的数据类型

C 结构体 | 菜鸟教程 (runoob.com)

共用体

在相同的内存位置存储不同的数据类型。以定义一个带有多成员的共用体,但是任何时候只能有一个成员带有值。共用体提供了一种使用相同的内存位置的有效方式。

//union结构体
union Data
{
   int i;
   float f;
   char  str[20];
};//所占空间大小为,类型中占位最大的
调用
    union Date data;
    data.i=20;
//如果同时调用data.f   ,data.i会损坏

位域

struct packed_struct {
  unsigned int f1:1;//4位现只需要1位
  unsigned int   :1;//空域,占位,该1位不能使用
  unsigned int f3:1;//从下一个单元开始存放
  unsigned int f4:1;
  unsigned int type:4;
  unsigned int my_int:9;
} pack;
调用
位域变量名.位域名      // 给位域赋值(应注意赋值不能超过该位域的允许范围)
位域变量名->位域名
 	pbit=&bit;    /* 把位域变量 bit 的地址送给指针变量 pbit */
    pbit->a=0;    /* 用指针方式给位域 a 重新赋值,赋为 0 */
    pbit->b&=3;    /* 使用了复合的位运算符 "&=",相当于:pbit->b=pbit->b&3,位域 b 中原有值为 7,与 3 作按位与运算的结果为 3(111&011=011,十进制值为 3) */
    pbit->c|=1;    /* 使用了复合位运算符"|=",相当于:pbit->c=pbit->c|1,其结果为 15 */

typedef

用来为类型取一个新名字

typedef struct Books
{
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
} Book;
/*类型位Book*/
对比typedef #define
  1. #define是C指令,为个数据类型定义别名
  2. #define不仅可以为类型定义别名,也能为数值定义别名,typedef只能为类型定义符号名称
  3. typedef由编译器执行解释,#define由预编译器处理

i/o

C 语言中的 I/O (输入/输出) 通常使用 printf() 和 scanf() 两个函数。

在这里插入图片描述

%d整型 **f%**浮点型

getchar() putchar()
  • int getchar(void) 函数从屏幕读取下一个可用的字符,并把它返回为一个整数。这个函数在同一个时间内只会读取一个单一的字符。可以在循环内使用这个方法,从屏幕上读取多个字符。

  • int putchar(int c) 函数把字符输出到屏幕上,并返回相同的字符。这个函数在同一个时间内只会输出一个单一的字符。可以在循环内使用这个方法,以便在屏幕上输出多个字符。

  • #include <stdio.h>
     
    int main( )
    {
       char str[100];
     
       printf( "Enter a value :");
       gets( str );
     
       printf( "\nYou entered: ");
       puts( str );
       return 0;
    }
    

在这里插入图片描述

scanf() print()
  • int scanf(const char *format, …) 函数从标准输入流 stdin 读取输入,并根据提供的 format 来浏览输入。

  • int printf(const char *format, …) 函数把输出写入到标准输出流 stdout ,并根据提供的格式产生输出。

  • format 可以是一个简单的常量字符串,但是您可以分别指定 %s、%d、%c、%f 等来输出或读取字符串、整数、字符或浮点数。

#include <stdio.h>
int main( ) {
 
   char str[100];
   int i;
 
   printf( "Enter a value :");
   scanf("%s %d", str, &i);
 
   printf( "\nYou entered: %s %d ", str, i);
   printf("\n");
   return 0;
}

在这里插入图片描述
在这里插入图片描述

32765 我不知道是不是5个backspce的原因

文件读写

/*在Linux系统中*/
#include <stdio.h>
 
int main()
{
   FILE *fp = NULL;
 
   fp = fopen("/tmp/test.txt", "w+");
   fprintf(fp, "This is testing for fprintf...\n");
   fputs("This is testing for fputs...\n", fp);
   fclose(fp);
}

在这里插入图片描述

预处理器

C 预处理器只不过是一个文本替换工具而已,它们会指示编译器在实际编译之前完成所需的预处理。(cpp)

在这里插入图片描述

在这里插入图片描述

参数化的宏

可以使用参数化的宏来模拟函数

int square(int x) {
   return x * x;
}

/*可用#define square(x) ((x) * (x))写上面的代码*/
#include <stdio.h>
 
#define MAX(x,y) ((x) > (y) ? (x) : (y))
 
int main(void)
{
   printf("Max between 20 and 10 is %d\n", MAX(10, 20));  
   return 0;
}

头文件.h

包含了 C 函数声明和宏定义,被多个源文件中引用共享。有两种类型的头文件:程序员编写的头文件和编译器自带的头文件。需要使用 C 预处理指令 #include 来引用它。

int x;
#include "header.h"/*引用语法时要引用头文件*/
int main (void)
{
   puts (test ());//引用头文件中的操作
}
/*从多个不同的头文件中选择一个引用到程序中if elif*/
#if SYSTEM_1
   # include "system_1.h"
#elif SYSTEM_2
   # include "system_2.h"
#elif SYSTEM_3
   ...
#endif

强制类型转换

(type_name) expression

强制类型转换运算符的优先级大于除法,

在这里插入图片描述

错误处理

errno 、perror()、strerror()
  • perror() 函数显示您传给它的字符串,后跟一个冒号、一个空格和当前 errno 值的文本表示形式。
  • strerror() 函数,返回一个指针,指针指向当前 errno 值的文本表示形式。

递归(参考数据结构)

可变参数

int func(int, ... ) 
{
   .
   .
   .
}
 
int main()
{
   func(2, 2, 3);
   func(3, 2, 3, 4);
}

请注意,函数 func() 最后一个参数写成省略号,即三个点号(),省略号之前的那个参数是 int,代表了要传递的可变参数的总数。为了使用这个功能,您需要使用 stdarg.h 头文件,该文件提供了实现可变参数功能的函数和宏。具体步骤如下:

  • 定义一个函数,最后一个参数为省略号,省略号前面可以设置自定义参数。
  • 在函数定义中创建一个 va_list 类型变量,该类型是在 stdarg.h 头文件中定义的。
  • 使用 int 参数和 va_start 宏来初始化 va_list 变量为一个参数列表。宏 va_start 是在 stdarg.h 头文件中定义的。
  • 使用 va_arg 宏和 va_list 变量来访问参数列表中的每个项。
  • 使用宏 va_end 来清理赋予 va_list 变量的内存。

内存管理

在这里插入图片描述

动态分配内存

定义一个指针,指向未定义所需内存大小的字符,再根据需求来分配内存

 description = (char *)malloc( 200 * sizeof(char) );
/*通过调用函数 realloc() 来增加或减少已分配的内存块的大小*/
/* 使用 free() 函数释放内存 */
   free(description);

命令行参数

都可
int main( int argc, char *argv[] )
int main( int test_argc, char *test_argv[] )  

排序算法(数据结构)

冒泡
#include <stdio.h>
void bubble_sort(int arr[], int len) {
    int i, j, temp;
    for (i = 0; i < len - 1; i++)
        for (j = 0; j < len - 1 - i; j++)
            if (arr[j] > arr[j + 1]) {
                temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
}
int main() {
    int arr[] = { 22, 34, 3, 32, 82, 55, 89, 50, 37, 5, 64, 35, 9, 70 };
    int len = (int) sizeof(arr) / sizeof(*arr);
    bubble_sort(arr, len);
    int i;
    for (i = 0; i < len; i++)
        printf("%d ", arr[i]);
    return 0;
}
选择排序
void selection_sort(int a[], int len) 
{
    int i,j,temp;
 
    for (i = 0 ; i < len - 1 ; i++) 
    {
        int min = i;                  // 记录最小值,第一个元素默认最小
        for (j = i + 1; j < len; j++)     // 访问未排序的元素
        {
            if (a[j] < a[min])    // 找到目前最小值
            {
                min = j;    // 记录最小值
            }
        }
        if(min != i)
        {
            temp=a[min];  // 交换两个变量
            a[min]=a[i];
            a[i]=temp;
        }
        /* swap(&a[min], &a[i]);  */   // 使用自定义函数交換
    }
}
 
/*
void swap(int *a,int *b) // 交换两个变量
{
    int temp = *a;
    *a = *b;
    *b = temp;
}
*/
插入排序
void insertion_sort(int arr[], int len){
    int i,j,temp;
    for (i=1;i<len;i++){
            temp = arr[i];
            for (j=i;j>0 && arr[j-1]>temp;j--)
                    arr[j] = arr[j-1];
            arr[j] = temp;
    }
}

希尔排序

void shell_sort(int arr[], int len) {
    int gap, i, j;
    int temp;
    for (gap = len >> 1; gap > 0; gap = gap >> 1)
        for (i = gap; i < len; i++) {
            temp = arr[i];
            for (j = i - gap; j >= 0 && arr[j] > temp; j -= gap)
                arr[j + gap] = arr[j];
            arr[j + gap] = temp;
        }
}
归并排序
  1. 迭代法
int min(int x, int y) {
    return x < y ? x : y;
}
void merge_sort(int arr[], int len) {
    int* a = arr;
    int* b = (int*) malloc(len * sizeof(int));
    int seg, start;
    for (seg = 1; seg < len; seg += seg) {
        for (start = 0; start < len; start += seg + seg) {
            int low = start, mid = min(start + seg, len), high = min(start + seg + seg, len);
            int k = low;
            int start1 = low, end1 = mid;
            int start2 = mid, end2 = high;
            while (start1 < end1 && start2 < end2)
                b[k++] = a[start1] < a[start2] ? a[start1++] : a[start2++];
            while (start1 < end1)
                b[k++] = a[start1++];
            while (start2 < end2)
                b[k++] = a[start2++];
        }
        int* temp = a;
        a = b;
        b = temp;
    }
    if (a != arr) {
        int i;
        for (i = 0; i < len; i++)
            b[i] = a[i];
        b = a;
    }
    free(b);
}
  1. 递归法
void merge_sort_recursive(int arr[], int reg[], int start, int end) {
    if (start >= end)
        return;
    int len = end - start, mid = (len >> 1) + start;
    int start1 = start, end1 = mid;
    int start2 = mid + 1, end2 = end;
    merge_sort_recursive(arr, reg, start1, end1);
    merge_sort_recursive(arr, reg, start2, end2);
    int k = start;
    while (start1 <= end1 && start2 <= end2)
        reg[k++] = arr[start1] < arr[start2] ? arr[start1++] : arr[start2++];
    while (start1 <= end1)
        reg[k++] = arr[start1++];
    while (start2 <= end2)
        reg[k++] = arr[start2++];
    for (k = start; k <= end; k++)
        arr[k] = reg[k];
}
void merge_sort(int arr[], const int len) {
    int reg[len];
    merge_sort_recursive(arr, reg, 0, len - 1);
}
快速排序
  1. 迭代法
typedef struct _Range {
    int start, end;
} Range;
Range new_Range(int s, int e) {
    Range r;
    r.start = s;
    r.end = e;
    return r;
}
void swap(int *x, int *y) {
    int t = *x;
    *x = *y;
    *y = t;
}
void quick_sort(int arr[], const int len) {
    if (len <= 0)
        return; // 避免len等於負值時引發段錯誤(Segment Fault)
    // r[]模擬列表,p為數量,r[p++]為push,r[--p]為pop且取得元素
    Range r[len];
    int p = 0;
    r[p++] = new_Range(0, len - 1);
    while (p) {
        Range range = r[--p];
        if (range.start >= range.end)
            continue;
        int mid = arr[(range.start + range.end) / 2]; // 選取中間點為基準點
        int left = range.start, right = range.end;
        do
        {
            while (arr[left] < mid) ++left;   // 檢測基準點左側是否符合要求
            while (arr[right] > mid) --right; //檢測基準點右側是否符合要求
 
            if (left <= right)
            {
                swap(&arr[left],&arr[right]);
                left++;right--;               // 移動指針以繼續
            }
        } while (left <= right);
 
        if (range.start < right) r[p++] = new_Range(range.start, right);
        if (range.end > left) r[p++] = new_Range(left, range.end);
    }
}
  1. 递归法
void swap(int *x, int *y) {
    int t = *x;
    *x = *y;
    *y = t;
}
void quick_sort_recursive(int arr[], int start, int end) {
    if (start >= end)
        return;
    int mid = arr[end];
    int left = start, right = end - 1;
    while (left < right) {
        while (arr[left] < mid && left < right)
            left++;
        while (arr[right] >= mid && left < right)
            right--;
        swap(&arr[left], &arr[right]);
    }
    if (arr[left] >= arr[end])
        swap(&arr[left], &arr[end]);
    else
        left++;
    if (left)
        quick_sort_recursive(arr, start, left - 1);
    quick_sort_recursive(arr, left + 1, end);
}
void quick_sort(int arr[], int len) {
    quick_sort_recursive(arr, 0, len - 1);
}

C 语言实例 | 菜鸟教程 (runoob.com)

C 语言经典100例 | 菜鸟教程 (runoob.com)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值