首先讓我說我完全了解sprintf并printf在 C 中,但它們不符合我的需要。
我想要的是一個函式,它回傳格式化的字串,它的引數就像printf. 例如:
char *formatted = format("%c%s Mund%c!", '?', "Hola", 'o');
C有這樣的內置函式嗎?還是應該手動實施?如果是后者,如何實作這樣的功能?
值得一提的是:
- 字串長度未知
- 我不想列印字串
附帶說明:我不會使用 c ,而是使用 mingw-64 gcc
uj5u.com熱心網友回復:
除非您自己制作,否則沒有等效的函式,因為與 python 不同,C 中的字串是簡單的陣列,您需要負責分配所需的記憶體,將指標傳遞給函式,并在以后釋放它。這就是為什么在像 sprintf 這樣的函式中,您需要指定一個輸出陣列(并且可以選擇size在像 snprintf 這樣的變體中指定一個值)。
自定義實作將是這樣的(不包括錯誤檢查以保持簡單):
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#define STRSIZE 256
char* my_sprintf(const char* fmt, ...) {
/* Create a temporary buffer */
char temp[STRSIZE];
/* Get variadic arguments */
va_list args;
va_start(args, fmt);
/* Use the variadic argument variant of snprintf
* The return value is the number of characters that would have been written,
* if the buffer was sufficiently large. We use this to determine if we
* need to repeat on a larger buffer to account for strings of any length */
int len = vsnprintf(result, STRSIZE, fmt, args);
/* Cleanup */
va_end(args);
/* If the entire string fits in the temp buffer, return a copy */
if (len < STRSIZE)
return strdup(temp);
/* Otherwise, allocate enough memory and repeat */
char* result = (char*)malloc(len 1); // 1 for the null terminator
/* The variadic argument pack is consumed already, so recreate it */
va_start(args, fmt);
/* Use the variadic argument variant of sprintf
* (we already have enough allocated memory now, so no need for snprintf) */
vsprintf(result, fmt, args);
/* Cleanup */
va_end(args);
return result;
}
完成后,不要忘記釋放回傳的指標!
char* my_string = my_sprintf("My %s", "format");
...
free(my_string);
uj5u.com熱心網友回復:
@guard3清理方法。
嘗試列印到本地 buf 并復制它。
否則分配給所需的報告大小。
一路檢查錯誤。
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#define MY_APRINTF_BUF_SZ 256
#define MY_APRINTF_TRIES 3 // 2 or more
char* my_aprintf(const char *fmt, ...) {
va_list args;
char buf_local[MY_APRINTF_BUF_SZ];
char *buf = buf_local;
size_t buf_size = sizeof buf_local;
// Try a few times.
// Often the 1st time with a local buffer will be good enough for common sized strings
// Otherwise it "should" work on the 2nd time.
// Some corner cases may require more tries.
// Give up after a while.
for (int i = 0; i < MY_APRINTF_TRIES; i ) {
va_start(args, fmt); // TBD: Review if va_copy better/required
int length_needed = vsnprintf(buf, buf_size, fmt, args);
va_end(args);
// If encoded error occurred ...
if (length_needed < 0) {
if (buf == buf_local) {
return NULL;
}
break;
}
size_t size_needed = (unsigned) length_needed 1u;
if (size_needed <= buf_size) {
if (buf == buf_local) { // First time
buf = strdup(buf); // Code your own my_strdup if strdup not available.
}
return buf;
}
if (buf == buf_local) {
buf = NULL;
}
// Get more memory
void *ptr = realloc(buf, size_needed);
if (ptr == NULL) {
break;
}
buf = ptr;
buf_size = size_needed;
}
// Give up
free(buf);
return NULL;
}
示例使用
int main() {
char *s = my_aprintf("%d %s\n", 42, "Hello world!");
if (s) {
puts(s);
free(s);
}
}
如果需要的話
#include <errno.h>
#include <stdlib.h>
// Use as needed
char *my_strdup(const char *buf) {
size_t size = strlen(buf) 1u;
char *s = malloc(size);
if (s) {
memcpy(s, buf, size);
} else {
#ifdef ENOMEM
errno = ENOMEM;
#endif
}
return s;
}
uj5u.com熱心網友回復:
您有以下問題:
'?'
這不是一個單一的char。它是一個 UTF-8 字符,占用兩個 char. 在十六進制中,它是:
'\xC2\xA1'
或者,根據位元組順序:
'\xA1\xC2'
%c格式不能很好地處理這個問題。您想使用雙引號,因此它是一個字串并使用%s.
簡單的方法是向下傳遞緩沖區:
編輯:調整以添加緩沖區長度。
char *
generate(char *buf,size_t siz)
{
snprintf(buf,siz,"%s%s Mund%c!","?", "Hola", 'o');
buf[siz - 1] = 0;
return buf;
}
更接近您想要的是分配結果:
char *
generate(void)
{
char buf[1000];
snprintf(buf,sizeof(buf),"%s%s Mund%c!","?", "Hola", 'o');
buf[sizeof(buf) - 1] = 0;
char *format = strdup(buf);
return format;
}
請注意,c它沒有自動免費/垃圾收集,因此對于第二個示例,呼叫者必須執行以下操作(例如):
char *formatted = generate();
// do stuff with formatted ...
// free the result when no longer needed ...
free(formatted);
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/424891.html
