【C语言】关于我回头学的那些命令行参数等(七)

前言

我的第一门语言就是C,但是学艺不精,中途跑去学了C#和Java后,感觉到了C的重要性,毕竟是最接近底层的语言,又跑回来学C。

毕竟前两门的控制语句,变量什么的都是类似的,回到C后只需要学习一些特定C的语法,比如宏,预编译指令等等,这些对我来说都是陌生的词汇。

所以边学边记录一下以前的知识。



一、命令行参数

执行程序时,可以从命令行传值给 C 程序。这些值被称为命令行参数,它们对程序很重要,特别是当您想从外部控制程序,而不是在代码内对这些值进行硬编码时,就显得尤为重要了。

命令行参数是使用 main() 函数参数来处理的。

其中,

  • argc :传入参数的个数,默认为1(程序名称算一个)
  • argv[] :一个指针数组,指向传递给程序的每个参数。

下面是一个简单的实例,检查命令行是否有提供参数,并根据参数执行相应的动作:

#include <stdio.h>

int main( int argc, char *argv[] )  
{
    
    
   if( argc == 2 )
   {
    
    
      printf("The argument supplied is %s\n", argv[1]);
   }
   else if( argc > 2 )
   {
    
    
      printf("Too many arguments supplied.\n");
   }
   else
   {
    
    
      printf("One argument expected.\n");
   }
}

使用一个参数,编译并执行上面的代码,它会产生下列结果:

$./a.out testing
The argument supplied is testing

使用两个参数,编译并执行上面的代码,它会产生下列结果:

$./a.out testing1 testing2
Too many arguments supplied

不传任何参数,编译并执行上面的代码,它会产生下列结果:

$./a.out
One argument expected

应当指出的是,argv[0] 存储程序的名称,argv[1] 是一个指向第一个命令行参数的指针,*argv[n] 是最后一个参数。

如果没有提供任何参数,argc 将为 1,就是存储程序的名称。

如果传递了一个参数,argc 将被设置为 2,就是存储程序的名称加上第一个参数。

参数带空格的情况

多个命令行参数之间用空格分隔,但是如果参数本身带有空格,那么传递参数的时候应把参数放置在双引号 “” 或单引号 ‘’ 内部。

#include <stdio.h>

int main( int argc, char *argv[] )  
{
    
    
   printf("Program name %s\n", argv[0]);
 
   if( argc == 2 )
   {
    
    
      printf("The argument supplied is %s\n", argv[1]);
   }
   else if( argc > 2 )
   {
    
    
      printf("Too many arguments supplied.\n");
   }
   else
   {
    
    
      printf("One argument expected.\n");
   }
}

输入下列命令:

$./a.out “testing1 testing2”

结果如下:

Progranm name ./a.out
The argument supplied is testing1 testing2

因为下述命令的参数只算一个,包括程序自身的名称,所以进入了第一个条件判断。


二、递归

递归指的是在函数的定义中使用函数自身的方法。

#include <stdio.h>
 
double factorial(unsigned int i)
{
    
    
   if(i <= 1)
   {
    
    
      return 1;
   }
   return i * factorial(i - 1);
}
int  main()
{
    
    
    int i = 15;
    printf("%d 的阶乘为 %f\n", i, factorial(i));
    return 0;
}

结果如下:

15 的阶乘为 1307674368000.000000


三、线程

是的,C语言提供了线程支持。C11标准引入了一组线程相关的库函数和头文件,称为“Thread library”。

使用这些函数和头文件,可以在C程序中创建多并发执行的线程来实现异步处理、并行计算等功能。

下面是一个简单的示例代码,用于创建多个线程并在每个线程中运行一个简单的任务:

#include <stdio.h>
#include <threads.h>

int my_thread_func(void* arg)
{
    
    
	//1.arg是一个指向void类型的指针,表示不确定类型的数据地址。
	//2.(int*)arg将arg强制转换为指向整型数据的指针
	//这里假设arg所指向的内存储存了一个整型值。
	//3.*(int*)arg表示通过该指针访问其所指向的内存
	//并把其值作为整型数据返回给变量id。
    int id = *(int*)arg;
    printf("Thread %d is running", id);//打印线程ID
    return 0;
}

int main()
{
    
    
    const int num_threads = 4;//启动4个线程
    thrd_t threads[num_threads];//在循环中被赋值,保存新建线程的ID号
    int thread_args[num_threads];//参数1,2,3,4

    for (int i = 0; i < num_threads; i++) {
    
    
        thread_args[i] = i;
        //创建线程
        thrd_create(&threads[i], my_thread_func, &thread_args[i]);
    }

    for (int i = 0; i < num_threads; i++) {
    
    //遍历所有线程ID
        thrd_join(threads[i], NULL);
    }

    return 0;
}

这段程序启动了4个线程,每个线程都执行同一个函数my_thread_func,并把该函数所需的参数传递给线程。

具体解析如下:

  1. 首先定义了一个常量num_threads,值为4,表示要启动4个线程。

  2. 创建了两个数组:threadsthread_args。前者存储线程标识符(即线程ID),后者存储传递给线程函数的参数。其中,数组长度都为num_threads

  3. 进入循环体,遍历数组thread_args中的每一个元素。此时数组内的元素值分别为0、1、2、3。这些值将被传递给4个线程作为参数。

  4. 在循环体内部,调用了 thrd_create() 函数来创建线程,并将其标识符存储在数组 threads 中。该函数接受三个参数:

  • 第一个参数是指向线程ID的指针,用于保存新建线程的ID号。
  • 第二个参数是指向函数 my_thread_func() 的指针。当新建的线程开始运行时,它将执行这个函数。
  • 第三个参数是指向要传递给新建线程的数据所在内存地址的指针。
  1. 退出第一个循环体后,进入第二个循环体。遍历数组 threads[], 调用 thrd_join() 函数等待每个线程执行完成。该函数接受两个参数:
  • 第一个参数是线程ID。
  • 第二个参数为指向线程返回值的指针,因为这里用不到,所以传入了 NULL
  1. 所有线程执行完成后,程序退出并返回0。

最后,使用 thrd_join 函数在主线程中等待所有线程的结束并释放它们的资源。

值得注意的是,C语言标准库只提供了一些基本的线程操作函数和类型,例如创建、销毁、等待和同步线程等。

对于更高级别的功能,例如锁定和互斥、条件变量、信号量等需要使用其他库或实现。

那么C语言总结到这里基本就告一段落了,后面一些更高级的就以后在更新或者自己去学习吧。

猜你喜欢

转载自blog.csdn.net/qFAFAF/article/details/129935366