一起笨笨的学C——013变参

目录

前言

正文

类似scanf代码:

附加任务

vprintf

  后语

strtoi 和 strtol  都是 C 语言中用于将字符串转换为整数的函数,它们的作用是将一个字符串表示的数字转换为对应的整数值。(我的乌班图linux用不了strtoi)

如果你不想看我的输出,那本篇特色就是代码了,然后加一个开头的传送门,呵呵!



前言

        什么是变参函数?变形金刚?几经周转,了解了真相后,感觉变态函数更贴切!

        竟然是变态了,觉得脑瓜不够用的,或者没想深入从事程序编辑工作的,可以跳过了,为什么?这是肖老师说的!

        这个大大说,变参函数对写C程序不是必需的,他写了20多年(多少年是我瞎猜的)也就用20多次。

        不过嘛(有点大喘气呀,啊喂!),理解变参运作将会有助于你调试程序,并加深你对计算机的理解。

        具体表现在使用变参函数,你可以给你的库文件创建更好的接口。对于某些“构建者”函数、格式化函数,以及任何要取得可变参数的函数,他们用起来都很方便。

        嗨,要想用它实现日志打印,我不会,推荐一个传送门:https://blog.csdn.net/qq_65207641/article/details/132909901文章浏览阅读1.7k次,点赞34次,收藏51次。有时我们在使用C语言时可能会碰到这样的情况,希望函数带有可变数量的参数,而不是预定义数量的参数。为此C 语言为这种情况提供了一个解决方案,它允许您定义一个函数,能根据具体的需求接受可变数量的参数。使用方式为:其中,省略号表示可变参数列表,需要注意的是:如果你想使用可变参数列表,则至少有一个固定参数,即不存在下面的函数:我们C语言常用的和函数就是使用了可变参数列表的函数:对于可变参数列表,我们最关心的还是怎么将可变参数提取出来,关于可变参数的提取主要依赖一个类型和四个宏函数:,,,,,而这些类型和宏函_c语言可变参数https://blog.csdn.net/qq_65207641/article/details/132909901


正文

类似scanf代码:

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "dbg.h"

#define MAX_DATA 100

int read_string(char **out_string, int max_buffer)
{
	*out_string = calloc(1, max_buffer +1);
	check_mem(*out_string);

	char *result = fgets(*out_string,max_buffer, stdin);
	check(result != NULL, "Input error.");

	return 0;

error:
	if(*out_string) free(*out_string);
	*out_string = NULL;
	return -1;
}

int read_int(long *out_int)
{
	char *input = NULL;
	char *end = NULL;
	int rc = read_string(&input, MAX_DATA);
	check(rc == 0, "Failed to read number.");

	*out_int = strtol(input, &end, 10);//strtoi函数是标准库中不常见的函数,所以在一些编译环境中可能会出现找不到该函数的问题。你可以尝试使用更常见的函数strtol来代替strtoi
	check((*end == '\0' || *end =='\n') &&
			*input != '\0', "Invalid number: %s", input);

	free(input);
	return 0;

error:
	if (input) free(input);
	return -1;
}

int read_scan(const char *fmt, ...)
{
	int i = 0;
	int rc = 0;
	long *out_int = NULL;
	char *out_char = NULL;
	char **out_string = NULL;
	int max_buffer =0;

	va_list argp;
	va_start(argp, fmt);

	for(i =0; fmt[i] != '\0'; i++) {
		if(fmt[i] == '%') {
			i++;
			switch (fmt[i]) {
				case '\0':
					sentinel("INvail format, you ended witth %%.");
					break;

				case 'd':
					out_int = va_arg(argp, long *);
					rc = read_int(out_int);
					check(rc == 0, "Failed to read int.");
					break;

				case 'c':
					out_char = va_arg(argp, char *);
					*out_char = fgetc(stdin);
					break;

				case 's':
					max_buffer = va_arg(argp, int);
					out_string= va_arg(argp, char **);
					rc = read_string(out_string, max_buffer);
					check(rc ==0, "Failed to read string.");
					break;

				default:
					sentinel("Invalid format");

			}
		}else{
			fgetc(stdin);
		}

		check(!feof(stdin)&& !ferror(stdin), "Input error.");
	}

	va_end(argp);
	return 0;

error:
	va_end(argp);
	return  -1;
}

int main(int argc, char *argv[])
{
	char *first_name = NULL;
	char initial = ' ';
	char *last_name = NULL;
	long age = 0;

	printf("What;s your first name?");
	int rc = read_scan("%s", MAX_DATA, &first_name);
	check(rc == 0, "Failed first name.");

	printf("What's your initial?");
	rc = read_scan("%c\n", &initial);
	check(rc== 0, "Failed initial.");


	printf("What's your last name ?");
	rc = read_scan("%s:", MAX_DATA, &last_name);
	check(rc == 0, "Failed last name.");

	printf("How old are you?");
	rc = read_scan("%d", &age);
	check(rc == 0, "Failed to read ge.");

	printf("--- RESULTS ---\n");
	printf("First Name: %s", first_name);
	printf(":Initial: '%c'\n", initial);
	printf("Last Name: %s", last_name);
	printf("Age: %ld\n", age);

	free(first_name);
	free(last_name);
	return 0;

error:
	return -1;
}

 大大说,他的out函数很玄妙哦!恩,很绕。感兴趣的研究去吧,哈哈!

附加任务

写一个和printf类似的函数,让它使用变参系统。

我研究了下readscanf之后,以为printf也要遍历,也要解析。最后发现简简单单的几行代码就搞定了int read_printf(const char *fmt, ...)
 

此时真的要用消消乐里面的“一抹嘴”,来表达我的吃惊心态了!所以我扒了vprintf的皮,鳖孙!

vprintf

vprintf是C语言标准库中的一个函数,其原型和用法如下:

原型: int vprintf(const char *format, va_list arg);

用法: vprintf函数用于格式化输出,根据format字符串中的格式说明符将可变参数arg依次输出到标准输出流stdout。format字符串中的格式说明符指定了输出的格式,例如%d表示输出整数,%f表示输出浮点数,%s表示输出字符串等等。

具体用法如下:

  1. 包含头文件: #include <stdio.h> #include <stdarg.h>

  2. 定义格式字符串和可变参数列表: const char *format = "Hello, %s! Your age is %d."; char *name = "John"; int age = 30;

  3. 调用vprintf函数进行格式化输出: vprintf(format, arg);

  4. 结果输出: Hello, John! Your age is 30.

需要注意的是,vprintf函数接受一个格式字符串format和一个va_list类型的可变参数列表arg。可变参数列表arg需要使用stdarg.h头文件中提供的宏va_start、va_arg和va_end来获取和操作参数。在调用vprintf函数之前,需要通过va_start宏初始化arg,调用vprintf函数之后,需要通过va_end宏结束对可变参数的操作。

另外,vprintf函数的返回值为输出的字符数,如果发生错误则返回负值。

      

         

    


  后语

  1. strtoistrtol  都是 C 语言中用于将字符串转换为整数的函数,它们的作用是将一个字符串表示的数字转换为对应的整数值。(我的乌班图linux用不了strtoi)

    strtoi 是 C99 标准引入的函数,它的完整原型如下:

    int strtoi(const char *restrict str, char **restrict endptr, int base);
    

    strtoi 函数将字符串 str 转换为一个整数,并返回该整数值。可选的 base 参数表示字符串的进制数,默认为 10。endptr 参数是一个指向指针的指针,在函数执行完毕后,它会指向转换结束的位置。

    strtol 是较早期的函数,它的完整原型如下:

    long strtol(const char *restrict str, char **restrict endptr, int base);
    

    strtol 函数与 strtoi 函数类似,但返回的是 long 类型的整数值。

    主要的区别在于函数返回值的类型不同,strtoi 返回 int 类型,而 strtol 返回 long 类型。

    此外,strtol 函数还存在于 C89/90 标准中,因此在不支持 C99 标准的编译器中,只能使用 strtol 函数。而对于支持 C99 标准的环境,可以使用 strtoi 函数进行字符串到整数的转换,提供了更多的功能和选项。

    需要注意的是,在使用这两个函数时,需要确保字符串的格式正确,并进行错误处理,以避免潜在的错误。

  2. if(!(*end == '\0' || *end =='\n') &&*input != '\0')什么意思 

    这段代码是用于检查转换后的字符串结束位置的条件语句。让我们来解释一下条件语句的含义:

    *end == '\0' 表示转换结束后,字符串的下一个字符是字符串结束符'\0'。

    *end == '\n' 表示转换结束后,字符串的下一个字符是换行符'\n'。

    *input != '\0' 表示原始输入字符串不是空字符串。

    需要注意的是,endinput 是在之前的代码中声明和赋值的指针变量。

    整个条件语句的含义是,如果转换结束后的字符既不是字符串结束符('\0')也不是换行符('\n'),并且原始输入字符串不为空字符串,则条件为真。这意味着如果转换结束后还有额外的非结束符字符,或者原始输入字符串为空字符串,则条件为假。

  3. 本来想跳过的,没想到仔细研究一下,真的很有意思。变参变态的有点可爱啊!
  4. 变参的fmt我以为是第一个函数,我觉得它也要解析,最后发现它是最后一个传递给函数的已知的固定参数,即省略号之前的参数
  5. 学得越多,越发现肖老师真是功力深厚啊!(我不知道是不是夸他)反正他是以大神的角度写文章,也是写个准大神们看的。也就是说哪天我觉得入门程序员了,有那么几年实战经验了,回头看这个书应该还是有所得的。所以我还是在夸这本书,呵呵!
  6. 如果你不想看我的输出,那本篇特色就是代码了,然后加一个开头的传送门,呵呵!

                      

  • 9
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值