[英]String manipulation & memory allocation - C
我正在學習C.我有一個方法,需要3個字符串並將它們組合起來做一些操作。 以下是我使用GCC編譯器的第一個實現。
void foo(const char *p1, const char *p2, const char *p3)
{
size_t length = strlen(p1) + strlen(p2) + strlen(p3);
char combined[length + 1];
memset(combined, 0, length + 1);
strcat(combined, p1);
strcat(combined, p2);
strcat(combined, p3);
printf("Result : %s", combined);
}
int main()
{
foo("hello ", "world ", "how");
return 0;
}
這很好用。 但是當我使用cc -Wall -pedantic -g foo.c -o foo
編譯它時,我開始收到像ISO C90 forbids variable length array 'combined'
這樣的警告, ISO C90 forbids variable length array 'combined'
。 MSVC沒有編譯此代碼。 更改了代碼
void foo(const char *p1, const char *p2, const char *p3)
{
size_t length = strlen(p1) + strlen(p2) + strlen(p3);
char *combined = (char *) malloc(length + 1);
memset(combined, 0, length + 1);
strcat(combined, p1);
strcat(combined, p2);
strcat(combined, p3);
printf("Result : %s", combined);
free(combined);
}
問題
-Wall -pedantic
。 我也應該使用-ansi
嗎? MSVC中可用的等效標志是什么? 這很好用。 但是當我使用cc -Wall -pedantic -g foo.c -o foo編譯它時,我開始收到像ISO C90這樣的警告,禁止變量長度數組“組合”。
嘗試使用-std=c99
選項(gcc)進行編譯。
MSVC沒有編譯此代碼。 更改了代碼
如果可變長度數組不是標准的一部分,為什么GCC實現它?
VLA是ISO C99(gcc和g ++(作為擴展)支持VLA)的一部分。 MSVC仍然只支持C89。
我的代碼預計將在GCC和MSVC上編譯。
那么你不應該在代碼恕我直言中使用VLA。
memset
是浪費時間,但是因為它無論如何都會被覆蓋(讓你的第一個strcat
變成strcpy
)。 並且您應該始終檢查malloc
返回NULL。 無論! malloc
是你最好的選擇,特別是如果你想返回組合字符串。 -std=c89
標志或類似的東西。 無論如何,MSVC並不總是遵循標准:-) 我會選擇:
void foo (const char *p1, const char *p2, const char *p3) {
size_t length = strlen(p1) + strlen(p2) + strlen(p3);
char *combined = (char *) malloc(length + 1);
if (combined == NULL) {
printf("Result : <unknown since I could't get any memory>\n");
} else {
strcpy(combined, p1);
strcat(combined, p2);
strcat(combined, p3);
printf("Result : %s", combined);
free(combined);
}
}
或者,因為除了打印它之外你實際上沒有對字符串做任何事情:
void foo (const char *p1, const char *p2, const char *p3) {
printf("Result : %s%s%s", p1, p2, p3);
}
:-)
我見過的另一個策略是“只有你必須分配”策略:
void foo (const char *p1, const char *p2, const char *p3) {
char str1k[1024];
char *combined;
size_t length = strlen (p1) + strlen (p2) + strlen (p3) + 1;
if (length <= sizeof(str1k))
combined = str1k;
else
combined = malloc (length);
if (combined == NULL) {
printf ("Result : <unknown since I couldn't get any memory>\n");
} else {
strcpy (combined, p1);
strcat (combined, p2);
strcat (combined, p3);
printf ("Result : %s", combined);
}
if (combined != str1k)
free (combined);
}
如果組合的字符串適合,它使用堆棧存儲,如果不適合,則僅分配內存。 如果大量字符串組合到低於限制,這通常可以顯着提高速度。
可變長度陣列不是第一個ISO C標准(不同地稱為“C89”,“C90”或“ANSI C”)的一部分。 但是,它們是最新ISO C標准(稱為“C99”)的一部分。
GCC可以用幾種模式編譯你的代碼,包括“嚴格C90”,“C90-with-GNU-C-extensions”和“C99”(盡管它沒有完全實現C99,但它足夠接近大多數實際用途)。
默認情況下,GCC使用“C90-with-GNU-C-extensions”,這就是為什么您的代碼無需投訴即可編譯的原因。 使用-pedantic
告訴它通過相關標准(在本例中為C90)發出所有必需的警告,並且代碼需要這樣的警告。 如果你給GCC -std=c99 -pedantic
標志,告訴它根據C99基本標准編譯並發出所有必需的警告,你的代碼編譯得很好。
如果要確保代碼與基本C90標准兼容,則使用-std=c90 -pedantic
(或-ansi -pedantic
: -ansi
是編譯C代碼時-std=c90
的同義詞)。 請注意,MSVC不支持C99。
解決這些問題的一個非常常見的習慣是讓調用者管理內存。 因此,不是自己分配內存(使用堆棧上的可變長度數組或通過malloc
的東西,或其他任何東西),而是希望調用者提供內存。 考慮一下:
int foo(const char *p1, const char *p2, const char *p3, char *buf, size_t bufsize)
{
size_t requiredSize = strlen(p1) + strlen(p2) + strlen(p3) + 1;
if (!buf)
return requiredSize;
if (requiredSize > bufsize)
return -1;
buf[0] = '\0';
strcat(buf, p1);
strcat(buf, p2);
strcat(buf, p3);
return requiredSize;
}
int main()
{
/* simple case: caller knows that the buffer is large enough. */
char buf[ 1024 ];
foo( "Hello", "World", "Bar", buf, sizeof(buf) );
printf("Result : %s\n", buf);
/* complicated case: caller wants to allocate buffer of just the right size */
size_t bufsize = foo( "Hello", "World", "Bar", NULL, 0 );
char *buf2 = (char *)malloc(bufsize);
foo( "Hello", "World", "Bar", buf2, bufsize );
free( buf2 );
}
這種方法的優點是foo
永遠不會泄漏。 除此之外,調用者可以使用簡單的基於堆棧的數組,以防它適用於他。 如果他想知道確切的大小,他可以調用foo
並傳遞NULL
作為第四個參數。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.