[英]How do I sprintf an array given a unknown format string?
正如標題所述,如何在給定未知格式字符串的情況下sprintf一個數組? 即我如何填寫my_sprintf
?
char* my_sprintf(const char *format, char **args){
char *result = malloc(MAX_SIZE_STRING*sizeof(char));
// ???
return result;
}
int main(int argc, char *argv[]){
printf("%s\n", my_sprintf("%s %s %s", argv));
return 0;
}
(這個答案考慮了OP的評論“我只想用修飾符來表示%s”)
請注意, 可以構建自己的va_list
,但是這個細節是特定於實現的並且非常不可移植,因此我不打算走這條路。
這可以說是最簡單的方法:
if ( argc == 1 ) snprintf(buf, sizeof buf, format, argv[0]);
else if ( argc == 2 ) snprintf(buf, sizeof buf, format, argv[0], argv[1]);
else if ( argc == 3 ) snprintf(buf, sizeof buf, format, argv[0], argv[1], argv[2]);
// ...etc, so far as you want
你的工作argc
通過循環argv
,直到你找到NULL
( argv[argc]
保證是NULL
)。
此代碼使用固定緩沖區大小char buf[MAX_LENGTH];
,然后你可以strdup
創建你的返回值或其他什么。 如果你想避免MAX_LENGTH
限制,那么你必須為每種情況調用兩次snprintf
:一次找出所需的長度; 然后malloc
,然后再次調用它來進行實際打印。
如果你更喜歡一個不那么剪切和粘貼的版本,你需要一個算法大綱:
argc
format
。 (如果您正在編寫生成格式的代碼,您可以只提供令牌列表而不是字符串) snprintf(buf + upto, space_remaining, token, argv[i++]);
雖然這樣做,你需要跟蹤多少的buf
你已經使用了(和realloc
每一步吧,如果你打算使用雙snprintf
方法)。 在到達argc
之前檢查你是否停止。
今晚太多時間在我的手上,所以這里有一個簡單的 - 如果不是全部那么特別有效 - 的方式。 當你說“我只打算使用修飾符這樣的%s
”時,我會直截了當地告訴你,特別是這不會應付%%
等等:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const static size_t initial_list_size = 20;
/*
* Returns a list of indices of `format` at which the substring
* "%s" is located. -1 is the sentinel value for end of list.
* Caller is responsible for freeing the returned pointer.
*/
int * find_specifiers(const char * format) {
size_t list_size = initial_list_size, top = 0;
/* Dynamically allocate list for locations of specifiers */
int * loc_list = malloc(list_size * sizeof *loc_list);
if ( loc_list == NULL ) {
fputs("Error allocating memory.", stderr);
exit(EXIT_FAILURE);
}
loc_list[top] = -1;
/* Find all occurrences */
const char * needle = format;
while ( (needle = strstr(needle, "%s")) != NULL ) {
/* Add index of found substring to list */
loc_list[top++] = needle - format;
/* Increase size of list if necessary */
if ( top >= list_size ) {
list_size *= 2;
loc_list = realloc(loc_list, list_size * sizeof *loc_list);
if ( loc_list == NULL ) {
fputs("Error allocating memory.", stderr);
exit(EXIT_FAILURE);
}
}
/* Set new sentinel value and skip past current specifier */
loc_list[top] = -1;
needle += 2;
}
return loc_list;
}
/*
* Returns a dynamically allocated string equivalent to `format`
* with each occurrence in `format` of "%s" replaced with successive
* strings in the array pointed to by `args`. Caller is responsible
* for freeing the returned pointer.
*/
char * my_sprintf(const char *format, char **args){
int * loc_list = find_specifiers(format);
size_t outsize = strlen(format) + 1;
/* Calculate required size of output string */
for ( size_t i = 0; loc_list[i] != -1; ++i ) {
outsize += strlen(args[i]) - 2;
}
/* Allocate output string with calloc() to avoid
* the need to manually null-terminate. */
char *result = calloc(1, outsize);
if ( result == NULL ) {
fputs("Error allocating memory.", stderr);
exit(EXIT_FAILURE);
}
/* Copy `format`, and replace specifiers with
* successive strings contained in `args` */
size_t n_out = 0, current_spec = 0, n_fmt = 0;
while ( format[n_fmt] ) {
/* Copy the next argument */
if ( loc_list[current_spec] != -1 &&
n_fmt == (size_t) loc_list[current_spec] ) {
size_t n_arg = 0;
while ( args[current_spec][n_arg] ) {
result[n_out++] = args[current_spec][n_arg++];
}
++current_spec;
n_fmt += 2;
}
else {
/* Copy the next character of `format` */
result[n_out++] = format[n_fmt++];
}
}
free(loc_list);
return result;
}
int main(void){
char * args[] = {"These", "are", "args"};
char * result1 = my_sprintf("Arg 1: %s, Arg 2: %s, Arg 3 %s", args);
char * result2 = my_sprintf("There are no args here.", NULL);
printf("%s\n", result1);
printf("%s\n", result2);
free(result1);
free(result2);
return 0;
}
哪個輸出:
paul@MacBook:~/Documents/src/scratch$ ./mysprint
Arg 1: These, Arg 2: are, Arg 3 args
There are no args here.
paul@MacBook:~/Documents/src/scratch$
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.