C语言关于我回头学的那些命令行参数等

Posted 啥都不会吖

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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语言总结到这里基本就告一段落了,后面一些更高级的就以后在更新或者自己去学习吧。

Go语言-获取命令行参数

Go语言-获取命令行参数

1、flag库使用

Go语言标准库提供了用于快讯解析命令行参数的flag包,大致的使用步骤如下

a、通过flag.String(),flag.Bool(),flag.Int()等方式来定义命令行中需要使用的参数。

b、在定义完flag后,通过调用flag.Parse()来进行对命令行参数的解析。

c、获取flag.String(),flag.Bool(),flag.Int()等方法的返回值,即对应用户输入的参数。

需要注意的是flag.Xxx()返回的值是变量的内存地址,要获取值时要通过在变量前加*(星号)获取。

说明:

flag.Int、flag.Bool、flag.String这样的函数格式都是一样的,调用的时候需要传入3个参数

参数说明如下:

第一个arg表示参数名称,在控制台的时候,提供给用户使用。

第二个arg表示默认值,如果用户在控制台没用给该参数赋值的话,就会使用该默认值。

第三arg表示使用说明和描述,在控制台中输入-arg的时候会显示该说明,类似-help

看个完整的使用例子

package main

import (
	"flag"
	"fmt"
)

func main() {
	married:=flag.Bool("married",false,"Are you married?")
	age:=flag.Int("age",22,"How old are you?")
	name:=flag.String("name","","What your name?")
	var address string
	//flag.StringVar这样的函数第一个参数换成了变量地址,后面的参数和flag.String是一样的。
	flag.StringVar(&address,"address","GuangZhou","Where is your address?")
	flag.Parse() //解析输入的参数
	fmt.Println("输出的参数married的值是:",*married)//不加*号的话,输出的是内存地址
	fmt.Println("输出的参数age的值是:",*age)
	fmt.Println("输出的参数name的值是:",*name)
	fmt.Println("输出的参数address的值是:",address)

}

 运行结果:

输出的参数married的值是: false
输出的参数age的值是: 22
输出的参数name的值是:
输出的参数address的值是: GuangZhou

从运行结中可以看出,address参数我们并没有指定值,则输出的就是默认值

另外,-arg后面=号也不是必须的可以用空格代替。

如果要查看该程序的所有参数的使用,可以使用-help来查看

2、os库的使用

直接看例子

package main

import (
	"fmt"
	"os"
)

func main() {
	args:=os.Args //获取用户输入的所有参数
	if args==nil || len(args)<2{
		Usage() //如果用户内有输入,或参数个数不够,则调用该函数提示用户
		return
	}
	name:=args[1];
	age:=args[2]
	fmt.Println("your name is:",name,"
your age is:",age)

}
var Usage= func() {
	fmt.Println("you name?")
	fmt.Println("you age?")
}

 运行结果:

you name?
you age?

个人感觉还是flag获取参数好用一点,因为flag更贴切参数的用法,而且可以查看详情。

最后补充

package main

import "fmt"

func main() {
	var name string ="abc"
	var nameAddress *string =&name //如果要接受变量的存储地址,变量对应的类型前面要加*号
	fmt.Println("name 变量的存储地址:",&name)
	fmt.Println("nameAddress的值:",nameAddress)
	fmt.Println("&name==nameAddress?",&name==nameAddress)
	fmt.Println("nameAddress对应变量的值:",*nameAddress)
	//内存地址前面加*好可以看到对应的值了
	fmt.Println("name变量的值:",*&*&name) //*号和&号可以多次组合来使用,阅读的时候从右往左
}

运行结果:

name 变量的存储地址: 0xc0000321f0
nameAddress的值: 0xc0000321f0
&name==nameAddress? true
nameAddress对应变量的值: abc
name变量的值: abc

-------------------------------------------------------------------------

[理论]

&符号的意思是对变量取地址,如:变量a 的地址是&a 

*符号的意思是对指针取值,如:*&a,就是a变量所在地址的值,当然也就是a的值了

[简单的解释]

*和&可以互相抵消,同时注意,*&可以抵消掉,但&*是不可以抵消的 a和*&a是一样的,都是a的值,值为1(因为*&互相抵消掉了)

同理,a和*&*&*&*&a是一样的,都是1(因为4个*&互相抵消掉了)

 

 

 

 




以上是关于C语言关于我回头学的那些命令行参数等的主要内容,如果未能解决你的问题,请参考以下文章

关于C语言执行CMD命令的问题

文件拷贝,用C语言实现命令行式的COPY功能

一个C语言的小问题

高手求教!!!c语言中怎样读取命令行参数?

跪求C语言函数调用的详细过程,函数之间是怎么传递的,到底是怎么发生调用的,最好是视频

命令行参数在哪里?