目
目录
strtoi 和 strtol 都是 C 语言中用于将字符串转换为整数的函数,它们的作用是将一个字符串表示的数字转换为对应的整数值。(我的乌班图linux用不了strtoi)
如果你不想看我的输出,那本篇特色就是代码了,然后加一个开头的传送门,呵呵!
前言
什么是变参函数?变形金刚?几经周转,了解了真相后,感觉变态函数更贴切!
竟然是变态了,觉得脑瓜不够用的,或者没想深入从事程序编辑工作的,可以跳过了,为什么?这是肖老师说的!
这个大大说,变参函数对写C程序不是必需的,他写了20多年(多少年是我瞎猜的)也就用20多次。
不过嘛(有点大喘气呀,啊喂!),理解变参运作将会有助于你调试程序,并加深你对计算机的理解。
具体表现在使用变参函数,你可以给你的库文件创建更好的接口。对于某些“构建者”函数、格式化函数,以及任何要取得可变参数的函数,他们用起来都很方便。
正文
类似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表示输出字符串等等。
具体用法如下:
-
包含头文件: #include <stdio.h> #include <stdarg.h>
-
定义格式字符串和可变参数列表: const char *format = "Hello, %s! Your age is %d."; char *name = "John"; int age = 30;
-
调用vprintf函数进行格式化输出: vprintf(format, arg);
-
结果输出: 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函数的返回值为输出的字符数,如果发生错误则返回负值。
后语
-
strtoi
和strtol
都是 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
函数进行字符串到整数的转换,提供了更多的功能和选项。需要注意的是,在使用这两个函数时,需要确保字符串的格式正确,并进行错误处理,以避免潜在的错误。
-
if(!(*end == '\0' || *end =='\n') &&*input != '\0')什么意思
这段代码是用于检查转换后的字符串结束位置的条件语句。让我们来解释一下条件语句的含义:
*end == '\0'
表示转换结束后,字符串的下一个字符是字符串结束符'\0'。*end == '\n'
表示转换结束后,字符串的下一个字符是换行符'\n'。*input != '\0'
表示原始输入字符串不是空字符串。需要注意的是,
end
和input
是在之前的代码中声明和赋值的指针变量。整个条件语句的含义是,如果转换结束后的字符既不是字符串结束符('\0')也不是换行符('\n'),并且原始输入字符串不为空字符串,则条件为真。这意味着如果转换结束后还有额外的非结束符字符,或者原始输入字符串为空字符串,则条件为假。
- 本来想跳过的,没想到仔细研究一下,真的很有意思。变参变态的有点可爱啊!
- 变参的fmt我以为是第一个函数,我觉得它也要解析,最后发现它是最后一个传递给函数的已知的固定参数,即省略号之前的参数
- 学得越多,越发现肖老师真是功力深厚啊!(我不知道是不是夸他)反正他是以大神的角度写文章,也是写个准大神们看的。也就是说哪天我觉得入门程序员了,有那么几年实战经验了,回头看这个书应该还是有所得的。所以我还是在夸这本书,呵呵!
-
如果你不想看我的输出,那本篇特色就是代码了,然后加一个开头的传送门,呵呵!