代码之家  ›  专栏  ›  技术社区  ›  Navaneeth K N

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

  •  8
  • Navaneeth K N  · 技术社区  · 14 年前

    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’ . 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);
    }
    

    1. 这是正确的执行方式吗?
    2. 如果可变长度数组不是标准的一部分,那么GCC为什么要实现它呢?如果预期代码只能在GCC上编译,那么使用变量数组将是比使用malloc更好的选择?
    3. 我认为经验法则是,如果在编译时知道所需的内存,那么使用数组或者使用malloc来分配所需的内存。是这样吗?
    4. -Wall -pedantic . 我应该用吗 -ansi 我也是?MSVC中可用的等效标志是什么?
    4 回复  |  直到 14 年前
        1
  •  8
  •   Community CDub    4 年前

    这很有效。但是当我使用cc-Wall-pedantic-gfoo.c-ofoo编译这个时,我开始收到类似isoc90禁止可变长度数组组合的警告。

    尝试用编译 -std=c99

    MSVC没有编译此代码。把代码改成

    如果可变长度数组不是标准的一部分,那么GCC为什么要实现它呢?

    那么你不应该在你的代码IMHO中使用VLAs。

        2
  •  7
  •   paxdiablo    14 年前
    1. memset strcat 变成一个 strcpy ). 你应该 总是 malloc 返回NULL。
    2. C89/90不是当前的标准,C99是。而C1x就不远了。海湾合作委员会正在紧跟前沿。
    3. 仅当不需要本地数组在函数结束后继续存在时才使用它们。否则 马洛克 是你最好的选择,尤其是如果你想的话 返回
    4. 我认为海湾合作委员会 -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);
        }
    }
    

    或者,因为除了打印字符串之外,您实际上没有对字符串执行任何操作:

    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);
    }
    

    如果组合字符串合适,则使用堆栈存储,如果不合适,则只分配内存。如果大量字符串组合成小于限制值的字符串,这通常会导致速度大幅提高。

        3
  •  3
  •   caf    14 年前

    可变长度数组不是第一个isoc标准的一部分(不同地称为“C89”、“C90”或“ansic”)。然而,他们 最新ISO C标准(称为“C99”)的一部分。

    GCC可以在几种模式下编译您的代码,包括“strict C90”、“C90-with-GNU-C-extensions”和“C99”(尽管它没有)

    默认情况下,GCC使用“C90-with-GNU-C-extensions”,这就是为什么您的代码可以毫无怨言地编译。使用 -pedantic 告诉它发出相关标准(在本例中是C90)所要求的所有警告,这样的警告是代码所要求的。如果你给GCC -std=c99 -pedantic 标记,告诉它根据C99基本标准编译并发出所有必需的警告,您的代码编译得很好。

    如果要确保代码与基本C90标准兼容,请使用 -std=c90 -pedantic (或 -ansi -pedantic -ansi 是的同义词 -std=c90

        4
  •  0
  •   Frerich Raabe    14 年前

    解决这些问题的一个非常常见的习惯用法是让调用者管理内存。因此,与其自己分配内存(要么在堆栈上使用可变长度数组,要么 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 不会泄漏。除此之外,调用者还可以使用一个简单的基于堆栈的数组,以防它对他有用。如果他想知道确切的尺寸,他可以打电话 然后传球 NULL