字符串操作和内存分配 - C.

Nav*_*K N 8 c string portability

我正在学习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;
}
Run Code Online (Sandbox Code Playgroud)

这很好用.但是当我使用编译时cc -Wall -pedantic -g foo.c -o foo,我开始收到类似的警告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);
}
Run Code Online (Sandbox Code Playgroud)

问题

  1. 这是正确的实施吗?
  2. 如果可变长度数组不是标准的一部分,为什么GCC实现它?如果代码只能在GCC上编译,那么使用变量数组比使用malloc更好吗?
  3. 我认为拇指规则是,如果在编译时需要内存,则使用数组,否则使用malloc来分配所需的内存.它是否正确?
  4. 我的代码预计将在GCC和MSVC上编译.我通常会在GCC上发展.那么什么是确保最大可移植性的编译器标志?目前我正在使用-Wall -pedantic.我-ansi也应该用吗?MSVC中可用的等效标志是什么?
  5. 编写可移植C代码时需要考虑的其他常见问题是什么?

Pra*_*rav 8

这很好用.但是当我使用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.


pax*_*blo 7

  1. 是的.那里没有具体违反标准的行为.这memset是浪费时间,但是因为无论如何它都会被覆盖(让你的第一个strcat成为a strcpy).你应该总是检查malloc返回NULL.无论!
  2. C89/90不是现行标准,C99是.C1x并不是那么遥远.海湾合作委员会正在紧跟前沿.
  3. 如果您不需要它们在函数结束之后存活,则仅使用本地数组.否则malloc是最好的选择,特别是如果你想返回组合字符串.
  4. 我认为gcc有-std=c89旗帜或类似的东西.无论如何,MSVC并不总是遵循标准:-)
  5. 经常在两个平台上编译和测试它.这是唯一确定的方法.

我会选择:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

或者,因为除了打印它之外你实际上没有对字符串做任何事情:

void foo (const char *p1, const char *p2, const char *p3) {
    printf("Result : %s%s%s", p1, p2, p3);
}
Run Code Online (Sandbox Code Playgroud)

:-)

我见过的另一个策略是"只有你必须分配"策略:

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);
}
Run Code Online (Sandbox Code Playgroud)

如果组合的字符串适合,它使用堆栈存储,如果不适合,则仅分配内存.如果大量字符串组合到低于限制,这通常可以显着提高速度.