The Windows system USES the C language to write a single threaded file backup program

  • 2020-05-09 18:54:14
  • OfStack

Write it at the front

Source path: From-Path, the data you want to back up
Destination path: To-Path, where you plan to store your backup data
Think back a little bit to the code we wrote last time. The task of this time is to traverse the directory and its subdirectories, so what we need to do this time is to move the data we traversed last time to the place where we want them to go.
This involves two operations, traversal and copy, the first of which we implemented in the previous one, and can be used with a few small changes. The last one also needs to be completed by Windows API, as for which, I will talk about later.
Now let's do 1 magic, 3, 2, 1! :


 do{
   puts("-------------------------------------------------");
   fprintf(stdout, "The Default Path is : %s \n", DEFAULT_TO_PATH);
   fprintf(stdout, "Now The Path is   : %s \n", get_backup_topath());
   puts("-------------------------------------------------");
   puts("That is a System Back Up Software for Windows! ");
   puts("List of the software function : ");
   puts("1. Back Up ");
   puts("2. Set Back Up TO-PATH ");
   puts("3. Show TO-PATH History");
   puts("4. Read Me ");
   puts("5. Exit ");
   puts("-------------------------------------------------");

Slightly changed the interface.

Lines 3 and 4 have been added to the system default destination path and the currently used destination path.

Added the ability to view destination path history on line 4 from last.

Outside the main function you need extern DEFAULT_TO_PATH; Because it refers to a global variable in setPath.c.

Writing in the middle

We have mentioned to make the function function more clear, in order to achieve this purpose, we should use 1 some native library function package 1, let the possible error as far as possible in our own hands

The safety function

New safeFunc. h safeFunc c
Consider 1 of the functions we need to wrap: malloc, free, fopen, three library functions.

Do not use global error output alone in order to prevent the rear multithreaded implementation from producing more later.
Let me implement them 1
I will not omit something that seems unnecessary, such as a comment, but present it in its entirety. If you feel that the length is too long, you can choose to skip it.
Magic is coming. Three, two, one!

   


  #include <stdio.h> /* size_t */
   #include <stdlib.h>
   #include <setjmp.h>
   #define TRY_TIMES 3

   typedef struct _input_para{
     char * file; /*  The file name to open or create  */
     char * mode; /*  Open mode  */
   }params;

   jmp_buf malc_jmp; /*Malloc_s*/
   jmp_buf fopn_jmp; /*Fopen*/

   /**
    * @version 1.0 2015/10/01
    * @author wushengixin
    * @param  ...  See structure description 
          Can pass in any number, and the form is  .file = "xxx", .mode = "x"  The parameters of the 
    * function  To take the default parameters and call the function  Fopen  Open operation 
    */
   #define Fopen_s(...) Fopen((params){.file = NULL, .mode = "r", __VA_ARGS__})
   FILE* Fopen(const params file_open) ; 

   /**
    * @version 1.0 2015/10/01
    * @author wushengxin
    * param  sizes  Enter the size to be allocated 
    * function  Used to hide 1 Some error handling, and call malloc Library functions allocate space 
    */
   void * Malloc_s(size_t sizes);

   /**
    * @version 1.0 2015/10/01
    * @author wushengxin
    * @param  input  External incoming pointer waiting to be released 
    * function  Used to hide 1 Some error handling, and call free The library function releases the pointer 
    */
   void Free_s(void * input);

It USES some new features. If you use GCC/Clang as a compiler, remember to turn on -std =c11 support.

The   functions will not be explained in detail, but a few of them will be briefly explained, followed by the implementation code:


   FILE* Fopen(const params file_open)
   {
     int times = 0;
     FILE* ret_p = NULL;
     if (file_open.file == NULL)
     {
       fputs("The File Name is EMPTY! Comfirm it and Try Again", stderr);
       return ret_p;
     }
     setjmp(fopn_jmp); /* fopn_jmp To there */
     ret_p = fopen(file_open.file, file_open.mode);
     if (ret_p == NULL)
     {
       if (times++ < TRY_TIMES) 
       longjmp(fopn_jmp, 0); /* fopn_jmp From here */
       fprintf(stderr, "The File : %s Open with Mode (%s) Fail!\n", file_open.file, file_open.mode);
     }
     return ret_p;
   }

   void * Malloc_s(size_t sizes)
   {
     int times = 0;
     void * ret_p = NULL;
     if (sizes == 0)
       return NULL;
     setjmp(malc_jmp); /* malc_jmp To There */
     ret_p = malloc(sizes);
     if (ret_p == NULL)
     {
       if (times++ < TRY_TIMES) /* malc_jmp From Here */
         longjmp(malc_jmp, 0);
       fputs("Allocate Memory Fail!", stderr);
     }
     return ret_p;
   }

   void Free_s(void * input)
   {
     if (input == NULL)
     {
   #if !defined(NOT_DEBUG_AT_ALL)
       fputs("Sent A NULL pointer to the Free_s Function!" .  stderr);
   #endif
       return;
     }
     free(input);
     input = NULL;
   }

The first   function starts it with the externally defined macro 'Fopen_s', and there is no implementation to hide it.

The preprocessing mechanism is used in the last   function. If '#define NOT_DEBUG_AT_ALL' is defined in the header file, this output will not appear
Now that the security function is written, it's time to get down to business

setPath.h

The first thing we want to do is save the default destination path in the application. The first thing we want to do is use the constant #define...
Second, you should ensure that the current destination path is not accessed by other illegal channels, which should be stored in an array of static characters.
The next step is to provide a function as an interface to get the destination path get_backup_topath that is actually in use.
We also need to implement the previous implementation of repl_str once again, because the previous display function is only a test, and will not be applied to the application.
With these two functions in place, how does the implementation set up the path, store the path, and cache the history destination path using file flow operations


   #include "safeFunc.h"

   #define SELF_LOAD_DEFAULT_PATH "C:/"
   #define MIN_PATH_NAME _MAX_PATH /*  Minimum limit  */
   #define LARGEST_PATH_NAME 32767 /*  The maximum limit of the path  */

   /*
    * @version 1.0 2015/10/02
    * @author  wushengxin
    * @function  Used to return the destination path currently in use 
    */
   const char * get_backup_topath();

   /**
   * @version 1.0 2015/09/28
   * @author wushengxin
   * @param  src  Externally passed in for adjustment 
   * @function  Used to replace the path  /  for  \  the 
   */
   void repl_str(char * src);

The corresponding implementation of   defines a static array of characters, which can be seen in the header file, many of which are defined in 'showFiles'.

Functions defined by  , such as' repl_str ', need to implement ** in 'showFiles.c' by using '#if 0... Comment out #endif ', otherwise a redefinition error will occur.
setPath.c


   #include "setPath.h"

   static char to_path_buf[LARGEST_PATH_NAME] = SELF_LOAD_DEFAULT_PATH;
   const char * DEFAULT_TO_PATH = SELF_LOAD_DEFAULT_PATH;
   const int LARGEST_PATH = LARGEST_PATH_NAME;

   const char * get_backup_topath()
   {
     return to_path_buf;
   }

   void repl_str(char * src)
   {
     size_t length = strlen(src);
     for (size_t i = 0; i <= length; ++i)
     {
       if (src[i] == '/')
         src[i] = '\\';
     }
     return;
   }

With the above code, the main interface can run correctly again, so what remains is to implement, set the destination path, store the destination path to the local, and display the destination path, corresponding to the 2 and 3 of the main interface respectively.
How to achieve it is better. Before starting, analyze the situation 1 will encounter:
After we get the destination path, we copy it to the default path, to_path_buf, and store it in a local cache file so that we can use the path we used the last time the program starts
You can also use another file to store all the used history paths, including time information.
So this requires us to realize the function of storing the destination path first, then the function of setting the destination path, and finally the function of displaying the destination path
Note: two seemingly useless global variables (const) are set up for the visibility of other files and save a little bit of space relative to #define.

Store destination path store_hist_path

setPath.h


    #include <time.h>
    /**
     * @version 1.0 2015/10/02
     * @version wushengxin
     * @param  path  The path you need to store 
     * @function  Used to store paths to local files  "show_hist"  and  "use_hist" 
     */
    void store_hist_path(const char * path);
setPath.c

    void store_hist_path(const char * path)
    {
      time_t ctimes; 
      time(&ctimes); /*  To get the time  */
      FILE* input_use = Fopen_s(.file = "LastPath.conf", .mode = "w"); /*  Write overwrite every time  */
      FILE* input_show = Fopen_s(.file = "PathHistory.txt", .mode = "a");
      if (!input_show || !input_use)
      {
    #if !defined(NOT_DEBUG_AT_ALL)
        fputs("Open/Create the File Fail!", stderr);
    #endif
        return;
      }
      fprintf(input_use, "%s\n", path); /*  write  */
      fprintf(input_show, "%s %s", path, ctime(&ctimes));
      fclose(input_show);
      fclose(input_use);
      return;
    }

The use of the       time 'and' ctime 'functions is more fully described on the web and is not explained here.

Once       has finished storing the functions, it is time to read from the keyboard and set the default path
Set the destination path set_enter_path

Stop here and think 1, if the user enters the wrong path (invalid path or malicious path), should it also be read? So you should add a check to confirm the validity of the path.
setPath.h


    #include <string.h>
    #include <io.h> /* _access */
    enum {NOT_EXIST = 0, EXIST = 1};
    /**
     * @version 1.0 2015/10/02
     * @author  wushengxin
     * @function  Use to read the path entered from the keyboard and set it to the default path and store it. 
     */
    void set_enter_path();

    /**
     * @version 1.0 2015/10/02
     * @author  wushengxin
     * @param  path  The path to check 
     * @function  To check if the path entered by the user is valid 
     */
    int is_valid_path(const char * path);

setPath.c


    int is_valid_path(const char * path)
    {/* _access  Back to interpretation  */
      if (_access(path, 0) == 0) /*  If there is a  */
        return EXIST;
      else
        return NOT_EXIST;
    }

    void set_enter_path()
    {
      int intJudge = 0; /*  To determine whether to decide to complete the input  */
      char tmpBuf[LARGEST_PATH_NAME]; /**  Temporary buffer  **/
      while (1)
      {
        printf("Enter The Path You want!\n");
        fgets(tmpBuf, LARGEST_PATH_NAME*sizeof(char), stdin); /*  Gets the path to the input  */
        sscanf(tmpBuf, "%s", to_path_buf);
        if (is_valid_path(to_path_buf) == NOT_EXIST)
        {
          fprintf(stderr, "Your Enter is Empty, So Load the Default Path\n");
          fprintf(stderr, "%s \n", SELF_LOAD_DEFAULT_PATH);
          strcpy(to_path_buf, SELF_LOAD_DEFAULT_PATH);
        }
        fprintf(stdout, "Your Enter is \" %s \" ?(1 for yes, 0 for no) \n", to_path_buf);

        fgets(tmpBuf, LARGEST_PATH_NAME*sizeof(char), stdin);
        sscanf(tmpBuf, "%d", &intJudge); /*  Gets the input of the judgment number  */
        if (intJudge != 0)
        {
          if (to_path_buf[strlen(to_path_buf) - 1] != '/')
            strcat(to_path_buf, "/");/*  If the last 1 Character is not '/' , then add, it does not consider whether the boundary is crossed  */
          store_hist_path(to_path_buf);
          break;
        } /* if(intJudge) */
      }/* while (1) */
      return;
    }/* set_enter_path */

The function of       is a little bit more complicated > Check for path validity - > Read the judgment number - > Whether to end the loop '

     , where '_access' function has some origins, because this function is known to everyone is this form 'access', but because this form is **POSIX** standard, so **Windows** will be implemented as' _access ', the usage is the same, but the name is different.
Displays the history path show_hist_path

setPath.h


    /**
     * @version 1.0 2015/10/02
     * author  wushengxin
     * function  Used to display all history paths in a window 
     */
    void show_hist_path();

setPath.c


    void show_hist_path()
    {
      system("cls");
      char outBufName[LARGEST_PATH_NAME] = {'\0'};
      FILE* reading = Fopen_s(.file = "PathHistory.txt", .mode = "r");
      if (!reading)
      return;

      for (int i = 1; i <= 10 && (!feof(reading)); ++i)  
      {
        fgets(outBufName, LARGEST_PATH_NAME*sizeof(char), reading);
        fprintf(stdout, "%2d. %s", i, outBufName);
      }
      fclose(reading);
      system("pause");
      return;
    }

We have one more tie up to do

Initialization path
Every time the program starts, we will read the local file and get the last path used by the last program as the current destination path
Initializes the destination path init_path

setPath.h


  #include <stdio.h> /* size_t */
   #include <stdlib.h>
   #include <setjmp.h>
   #define TRY_TIMES 3

   typedef struct _input_para{
     char * file; /*  The file name to open or create  */
     char * mode; /*  Open mode  */
   }params;

   jmp_buf malc_jmp; /*Malloc_s*/
   jmp_buf fopn_jmp; /*Fopen*/

   /**
    * @version 1.0 2015/10/01
    * @author wushengixin
    * @param  ...  See structure description 
          Can pass in any number, and the form is  .file = "xxx", .mode = "x"  The parameters of the 
    * function  To take the default parameters and call the function  Fopen  Open operation 
    */
   #define Fopen_s(...) Fopen((params){.file = NULL, .mode = "r", __VA_ARGS__})
   FILE* Fopen(const params file_open) ; 

   /**
    * @version 1.0 2015/10/01
    * @author wushengxin
    * param  sizes  Enter the size to be allocated 
    * function  Used to hide 1 Some error handling, and call malloc Library functions allocate space 
    */
   void * Malloc_s(size_t sizes);

   /**
    * @version 1.0 2015/10/01
    * @author wushengxin
    * @param  input  External incoming pointer waiting to be released 
    * function  Used to hide 1 Some error handling, and call free The library function releases the pointer 
    */
   void Free_s(void * input);

0

setPath.c


  #include <stdio.h> /* size_t */
   #include <stdlib.h>
   #include <setjmp.h>
   #define TRY_TIMES 3

   typedef struct _input_para{
     char * file; /*  The file name to open or create  */
     char * mode; /*  Open mode  */
   }params;

   jmp_buf malc_jmp; /*Malloc_s*/
   jmp_buf fopn_jmp; /*Fopen*/

   /**
    * @version 1.0 2015/10/01
    * @author wushengixin
    * @param  ...  See structure description 
          Can pass in any number, and the form is  .file = "xxx", .mode = "x"  The parameters of the 
    * function  To take the default parameters and call the function  Fopen  Open operation 
    */
   #define Fopen_s(...) Fopen((params){.file = NULL, .mode = "r", __VA_ARGS__})
   FILE* Fopen(const params file_open) ; 

   /**
    * @version 1.0 2015/10/01
    * @author wushengxin
    * param  sizes  Enter the size to be allocated 
    * function  Used to hide 1 Some error handling, and call malloc Library functions allocate space 
    */
   void * Malloc_s(size_t sizes);

   /**
    * @version 1.0 2015/10/01
    * @author wushengxin
    * @param  input  External incoming pointer waiting to be released 
    * function  Used to hide 1 Some error handling, and call free The library function releases the pointer 
    */
   void Free_s(void * input);

1

      is done. For the last '8' line of this function, the usual 'fgets' and 'sscanf' are not used because to do so, a 'memset' function would need to be set to zero, which will be explained later.

Interpretation of memset
This function is actually slow to initialize large blocks of memory. Of course, the memory impact of our 30KB May not be that big, but after Megabyte, calling memset is a performance problem. In many cases, the compiler will automatically cancel the implicit call of memset when the high optimization level is turned on
An implicit call, such as line 2 of init_path, calls implicit memset when it declares and initializes the array with curly braces.

Writing in the middle

This completes most of the functionality of the interface, leaving the main function of backing up.
Before completing the backup, first think about how to construct the backup model

Since it is a backup, if you don't want to extend it to the form of multi-threading, you can refer to the first written traversal function (show_structure) to directly find the file and then call Windows API(described later) to copy. You don't need to save the file path to be backed up.
If multithreaded extensions are to be considered, we need to take the long view.
For a backup model, the best thing to do is to use a queue, still in the traversal mode, but save the file path found and put it in a fifo queue, so that we can ensure a clear model reference when extending to multiple threads.
The task now is to implement the queue model for backup.
Queuing models

There should be 1 container space for the path There are signs at the beginning and end of the line O(1) complexity checks whether the queue is an empty interface or flag O(1) the interface or flag of complexity that returns the container capacity, which should be fixed

Use some object-oriented dark magic and save some action functions to prevent code clutter.

Initialization function Release function Pop-up operation function Press in operation function Queue entity

Considering that what is to be stored is a string, and because of the parameter requirements of Windows API, we need to store two paths for one file < Source path, destination path > , for which another path model structure should be used to wrap them, and the space type will be changed by 1
New Queue. h Queue c

Queue.h


  #include <stdio.h> /* size_t */
   #include <stdlib.h>
   #include <setjmp.h>
   #define TRY_TIMES 3

   typedef struct _input_para{
     char * file; /*  The file name to open or create  */
     char * mode; /*  Open mode  */
   }params;

   jmp_buf malc_jmp; /*Malloc_s*/
   jmp_buf fopn_jmp; /*Fopen*/

   /**
    * @version 1.0 2015/10/01
    * @author wushengixin
    * @param  ...  See structure description 
          Can pass in any number, and the form is  .file = "xxx", .mode = "x"  The parameters of the 
    * function  To take the default parameters and call the function  Fopen  Open operation 
    */
   #define Fopen_s(...) Fopen((params){.file = NULL, .mode = "r", __VA_ARGS__})
   FILE* Fopen(const params file_open) ; 

   /**
    * @version 1.0 2015/10/01
    * @author wushengxin
    * param  sizes  Enter the size to be allocated 
    * function  Used to hide 1 Some error handling, and call malloc Library functions allocate space 
    */
   void * Malloc_s(size_t sizes);

   /**
    * @version 1.0 2015/10/01
    * @author wushengxin
    * @param  input  External incoming pointer waiting to be released 
    * function  Used to hide 1 Some error handling, and call free The library function releases the pointer 
    */
   void Free_s(void * input);

2

5 typedef don't know if there is 1 meng at hand. I hope I can understand it well

The first two are declarations of the structure, corresponding to the queue model and the path model, respectively.

The last two are function Pointers, which are placed in structs so that the C structs can also have some simple object-oriented functions, such as member functions, by assigning values to variables of the function pointer type. The example becomes more obvious later. Try reading 1. It's easy.


  struct _combine{
  char * src_from_path; /*  The source path  */
  char * dst_to_path;  /*  Objective the path  */
  };

  struct _vector_queue{
    combine **   path_contain; /*  The container body that stores the path  */
    unsigned int  rear;     /*  Of the coordinates  */
    unsigned int  front;    /*  First coordinate team  */
    int       empty;    /*  Whether is empty  */
    unsigned int  capcity;   /*  Container capacity  */
    fpPushBack   PushBack; /*  Push the element to the end of the line  */
    fpPopFront   PopFront; /*  Lead the team out  */
    fpDelete    Delete;  /*  Destructions free up the entire queue space  */
  };

  /**
   * @version 1.0 2015/10/03
   * @author  wushengxin
   * @param  object  A pointer to an object passed in from the outside  this
   * @function  Initializes the queue model, establishes the queue entity, allocates space, and sets properties. 
   */
  int newQueue(queue* object);

As you can see, the function pointer type at the top is used in the body of the structure, and one initialization function is missing because it is not intended to be a member function.

When in use, you can directly obj_name.PushBack (... . ,...). ;

See the implementation section below for more details. The three functions that become member functions will be implemented as static functions and will not be accessed by the outside world.

queue.c


  #include <stdio.h> /* size_t */
   #include <stdlib.h>
   #include <setjmp.h>
   #define TRY_TIMES 3

   typedef struct _input_para{
     char * file; /*  The file name to open or create  */
     char * mode; /*  Open mode  */
   }params;

   jmp_buf malc_jmp; /*Malloc_s*/
   jmp_buf fopn_jmp; /*Fopen*/

   /**
    * @version 1.0 2015/10/01
    * @author wushengixin
    * @param  ...  See structure description 
          Can pass in any number, and the form is  .file = "xxx", .mode = "x"  The parameters of the 
    * function  To take the default parameters and call the function  Fopen  Open operation 
    */
   #define Fopen_s(...) Fopen((params){.file = NULL, .mode = "r", __VA_ARGS__})
   FILE* Fopen(const params file_open) ; 

   /**
    * @version 1.0 2015/10/01
    * @author wushengxin
    * param  sizes  Enter the size to be allocated 
    * function  Used to hide 1 Some error handling, and call malloc Library functions allocate space 
    */
   void * Malloc_s(size_t sizes);

   /**
    * @version 1.0 2015/10/01
    * @author wushengxin
    * @param  input  External incoming pointer waiting to be released 
    * function  Used to hide 1 Some error handling, and call free The library function releases the pointer 
    */
   void Free_s(void * input);

4

In the initialization function, you can see that the head and tail of the queue and the capacity are set, container space is allocated, and member functions are configured.

In the last three configuration function statements, push_back, pop_front, del_queue are implemented by static.

However, since there is no declaration, be sure to put the implementation of the three static functions in front of newQueue


  #include <stdio.h> /* size_t */
   #include <stdlib.h>
   #include <setjmp.h>
   #define TRY_TIMES 3

   typedef struct _input_para{
     char * file; /*  The file name to open or create  */
     char * mode; /*  Open mode  */
   }params;

   jmp_buf malc_jmp; /*Malloc_s*/
   jmp_buf fopn_jmp; /*Fopen*/

   /**
    * @version 1.0 2015/10/01
    * @author wushengixin
    * @param  ...  See structure description 
          Can pass in any number, and the form is  .file = "xxx", .mode = "x"  The parameters of the 
    * function  To take the default parameters and call the function  Fopen  Open operation 
    */
   #define Fopen_s(...) Fopen((params){.file = NULL, .mode = "r", __VA_ARGS__})
   FILE* Fopen(const params file_open) ; 

   /**
    * @version 1.0 2015/10/01
    * @author wushengxin
    * param  sizes  Enter the size to be allocated 
    * function  Used to hide 1 Some error handling, and call malloc Library functions allocate space 
    */
   void * Malloc_s(size_t sizes);

   /**
    * @version 1.0 2015/10/01
    * @author wushengxin
    * @param  input  External incoming pointer waiting to be released 
    * function  Used to hide 1 Some error handling, and call free The library function releases the pointer 
    */
   void Free_s(void * input);

5

One at a time. One at a time

del_queue: release the function and call Free_s directly

push_back: pressure into the function, the external into the path of the two original no strings, combined into one combine, and pressure into the path, whether the collocation is empty every time mark, actually have the suspicion of redundant code in this function, one function should be separated, is dedicated to the distribution of three space, prevent the function is too long (line close to 40)

pop_front: the function that pops up combine, the head of the queue, for replication, but there is a danger that you will release the work to someone else. If you are not careful, the danger is a memory leak.

There is no special provision for an interface to determine if it is empty, because when compiler 1 optimizes, it also optimizes the interface to use members directly, some form of inlining.

With the queue model designed, you can start to design the backup model
Backup model can recall the ergodic function before 1, the general structure is 1, only here in order to expand into multithreading, we need to add some multithreaded call functions, and to normalize, we need to add 1 level 2 interface
First design 1 and 2 level interface

Level 2 interface

So think 1, what is this interface going to do
Select whether to start the backup
And the source path needs to be entered here
Return to the previous level
New backup.h backup.c file
After selecting 1 in the main interface, the level 2 interface function is called
Lists the options for the level 2 interface
1 Start Back up
2 Back To last level
backup.h


  #include <stdio.h> /* size_t */
   #include <stdlib.h>
   #include <setjmp.h>
   #define TRY_TIMES 3

   typedef struct _input_para{
     char * file; /*  The file name to open or create  */
     char * mode; /*  Open mode  */
   }params;

   jmp_buf malc_jmp; /*Malloc_s*/
   jmp_buf fopn_jmp; /*Fopen*/

   /**
    * @version 1.0 2015/10/01
    * @author wushengixin
    * @param  ...  See structure description 
          Can pass in any number, and the form is  .file = "xxx", .mode = "x"  The parameters of the 
    * function  To take the default parameters and call the function  Fopen  Open operation 
    */
   #define Fopen_s(...) Fopen((params){.file = NULL, .mode = "r", __VA_ARGS__})
   FILE* Fopen(const params file_open) ; 

   /**
    * @version 1.0 2015/10/01
    * @author wushengxin
    * param  sizes  Enter the size to be allocated 
    * function  Used to hide 1 Some error handling, and call malloc Library functions allocate space 
    */
   void * Malloc_s(size_t sizes);

   /**
    * @version 1.0 2015/10/01
    * @author wushengxin
    * @param  input  External incoming pointer waiting to be released 
    * function  Used to hide 1 Some error handling, and call free The library function releases the pointer 
    */
   void Free_s(void * input);

6

The first is' switch ', 'case 1', wrapped in ** curly braces **, so that you can define the ** local variable **, directly after the colon is defined as ** compilation error **, which is probably less useful, but I mention it here, and I mentioned it earlier.
Let me write it in the last square

All that's left is to write the main functional functions and thread calls.


Related articles: