【问题标题】:Unix/C - 2 methods have different behaviourUnix/C - 2 方法有不同的行为
【发布时间】:2012-11-12 13:30:27
【问题描述】:

我是 UNIX C 开发的初学者,需要一点帮助。我有这两个功能:

void edit_char(){

     int i;
     int length = strlen(expression);
     char *tmp = (char *) malloc((length+1)*sizeof(char));
     pom[0]='*';
     for(i=1;i<length+1;i++){
         tmp[i] = expression[i-1];
     }
     strcpy(expression,tmp);
     free((void *) tmp);
 }



 char *edit_char2(char *string){

     int i;
     int length = strlen(string);
     char *tmp = (char *) malloc((length+1)*sizeof(char));
     tmp[0]='/';
     for(i=1;i<length+1;i++){
         tmp[i] = string[i-1];
     }
     strcpy(string,tmp);
     free((void *) tmp);
     return string;
  }

edit_char() 编辑全局变量char *expression - 它在开头放置一个符号“*”。第二个 edit_char2() 几乎相同,但不是编辑全局变量,而是从参数编辑字符串。

第一个函数工作正常,问题出在第二个函数的 tmp 变量上。 Malloc 不返回大小为 (length+1) 的空字符数组。它返回“xd\372\267xd\372\267\020”。

这是什么原因造成的?

【问题讨论】:

  • malloc 返回的内存内容未定义。它可以是任何东西。如果您想要零初始化内存,请使用calloc
  • Bwware,你试图做的事情是不可能的/不是这样的。您不能只是神奇地将内存“添加”到现有指针。请看我的回答。

标签: c function unix char malloc


【解决方案1】:

如前所述,您的代码将不起作用。

在这两个函数中使用strcpy(target, tmp) 时出现错误。您需要了解,这样做几乎肯定会溢出target 指向的内存。如果 target 只指向 strlen(target + 1) 的数组(target 中的所有字符加上一个尾随的 NULL),那么您将复制 tmp 的内容太短的一个内存数组 char。为了说明这一点,运行一个循环,例如:

/* allocate two strings, containing copies
   of constant string "Hello World" */
local_string = strdup("Hello World");
expression = strdup("Hello World");
for (i = 0; i < 100; i++) {
    edit_char();
    edit_char2(local_string);
    printf("global_string after: [%s]\n", expression);
    printf("local_string after: [%s]\n", local_string);
}

几乎总是会导致程序异常终止,早在第 100 次迭代之前。在 Debian Linux Squeeze 上,我得到以下输出:

user@host$ ./a.out
global_string before: [Hello World]
local_string before: [Hello World]
global_string after: [*Hello World]
[...]
global_string after: [************Hello World]
local_string after: [////////////Hello World]
*** glibc detected *** ./a.out: double free or corruption (!prev): 0x00000000020e2050

您需要使用更多的指针魔术才能实现您想要的。这是一个工作示例,设计改进限制了代码重复:

输出

 user@host$ ./a.out
global_string before: [Hello World]
local_string before: [Hello World]
global_string after: [*Hello World]
local_string after: [/Hello World]

代码

#include     <stdlib.h>
#include     <string.h>
#include     <stdio.h>

char        *global_string;

void        add_one_leading_character(char leading, char **pointer_to_string)
{

    char    *new_string;
    char    *old_string;

    /* old_string will hold the content of
       pointer_to_string, for convenience */
    old_string = *pointer_to_string;
    /* allocate a new, empty string
       (= filled with NULLs) holding enough space
       for an additional character */
    new_string  = calloc(sizeof(*old_string), strlen(old_string) + 2);
    /* new_string now holds the leading character,
       followed by NULLs */
    new_string[0] = leading;
    /* concatenate the old_string to the new_string */
    strcat(new_string, old_string);
    /* make the pointer parameter points to the
       address of new_string */
    *pointer_to_string = new_string;
    /* free the memory pointed by old_string */
    free(old_string);
}

int        main(int ac, char **av)
{
    char   *local_string;

    /* allocate two strings, containing copies
       of constant string "Hello World" */
    local_string = strdup("Hello World");
    global_string = strdup("Hello World");
    printf("global_string before: [%s]\n", global_string);
    printf("local_string before: [%s]\n", local_string);
    /* add leading characters */
    add_one_leading_character('/', &local_string);
    add_one_leading_character('*', &global_string);
    printf("global_string after: [%s]\n", global_string);
    printf("local_string after: [%s]\n", local_string);
}

【讨论】:

    【解决方案2】:

    malloc 只是返回一个指向新分配的内存的指针,它不被认为是“空的”。如果你想“清空”它 - 即用 NULL 填充你的内存,你需要手动完成需要使用 calloc 或手动填充,例如:

    编辑: 另外我认为,由于您要向每个字符串添加一个字符,因此您不应该使用

    newstring = malloc((strlen(string) + 1) * sizeof(char))
    

    而是

    newstring = malloc((strlen(string) + 2) * sizeof(char))
    

    为新字符和终止\0 分配空间。

    EDIT2:这也意味着你的函数不能工作/不安全!您正在尝试使 stringexpression 包含比最初分配给它们的字符多 1 个字符!

    【讨论】:

    • calloc 将是一种更标准/更便携的零填充新分配内存的方式
    【解决方案3】:
     tmp[0]='/';
     for(i=1;i<length+1;i++){
         tmp[i] = string[i-1];
     }
    

    您没有复制string 的尾随空字符。这是strcpy(string,tmp);所需要的

    请注意,您可以使用memmove 代替for 循环来执行复制。另请注意,malloc 的返回值的强制转换不是必需的,应该避免。 free 参数的强制转换也不是必需的。

    【讨论】:

      猜你喜欢
      • 2011-02-18
      • 2017-03-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-08
      • 2018-04-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多