C char指针vs指向char数组的指针,增加动态分配

时间:2011-05-31 21:05:21

标签: c

我是C新手,我很难理解下面的代码块无效的原因。

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

int main()
{
    char *src = "http://localhost";

    /* THIS WORKS
       char scheme[10];
       char *dp = scheme;
     */

    //DOESN'T WORK
    char *dp = malloc(10);

    while (*src != ':') {
        *dp = *src;
        src++;
        dp++;
    }
    *dp = '\0';

    /* WORKS
       puts(scheme)
     */

    //DOESN'T WORK
    puts(dp);
}

预期输出为http到标准输出。在这两种情况下,dp都应该是指向char指针数组(char **)的指针。但是,在使用malloc方法时,它什么都不打印。我通过GDB运行代码,我的srcdp一次被删除1个字符。如果我将while循环包含在函数调用中,它就可以工作。我认为原因是因为参数被评估为副本。但是,我读到数组是异常并作为指针传递。现在我很困惑。我可以解决这个问题,但我试图理解为什么这种方式不起作用。

4 个答案:

答案 0 :(得分:10)

您正在更改循环中的dp

dp = malloc(10);

假设dp的值为0x42000000

while () {
    dp++;
}

假设循环次数为4次,因此dp的值为0x42000004

*dp = 0;

现在您在dp

指向的地址处放置了一个空字符
puts(dp);

然后你尝试打印那个null:)

保存dp并打印保存的值

dp = malloc(10);
saveddp = dp;
/* ... */
puts(saveddp);
free(saveddp); /* for completeness */

它适用于scheme,因为scheme是一个数组而您无法更改该地址!

答案 1 :(得分:4)

循环结束后,dp指向分配字符串的末尾。您需要在dp之后立即保存malloc并增加副本,而不是原始指针到开头。

答案 2 :(得分:2)

在循环开始之前,dp指向已分配的内存的开头。在每次迭代中,将src指向的字符复制到当前指向的dp位置,并前进dp指向的一个内存位置。在循环结束时dp指向您已分配p的字符'\0'后面的内存位置。当您尝试使用puts (dp)打印字符串,因为dp的内容已更改,现在指向复制的最后一个字符后的位置,它将从该位置开始打印地点。它将打印一个空字符串,因为dp指向的第一个位置是空字符。

循环前

+----------+
|   src    |
+----------+
   |
   | 
   V
+-----+-----+-----+-----+-----+-----+-----+----       ----+----+
|  h  |  t  |  t  |  p  |  :  |  /  |  /  |     . . .   ? |  ? |
+-----+-----+-----+-----+-----+-----+-----+----       ----+----+

+----------+
|    dp    |
+----------+
   |
   | 
   V
+-----+-----+-----+-----+-----+-----+-----+----       ----+----+
|     |     |     |     |     |     |     |     . . .     |    |
+-----+-----+-----+-----+-----+-----+-----+----       ----+----+

循环后(使用dp = malloc(10))

                      +----------+
                      |   src    |
                      +----------+
                           |
                           | 
                           V
+-----+-----+-----+-----+-----+-----+-----+----       ----+----+
|  h  |  t  |  t  |  p  |  :  |  /  |  /  |     . . .     |  ? |
+-----+-----+-----+-----+-----+-----+-----+----       ----+----+

                      +----------+
                      |    dp    |
                      +----------+
                           |
                           | 
                           V
+-----+-----+-----+-----+-----+-----+-----+----       ----+----+
|  h  |  t  |  t  |  p  |  \0 |     |     |     . . .     |    |
+-----+-----+-----+-----+-----+-----+-----+----       ----+----+

注意puts (dp)将从上面指出的位置开始打印。 这不会得到预期的输出。还因为你没有保存过 您实际分配的dp的原始地址。你不能 在循环之后恢复它。

循环后(使用dp =&amp; scheme)

                      +----------+
                      |   src    |
                      +----------+
                           |
                           | 
                           V
+-----+-----+-----+-----+-----+-----+-----+----       ----+----+
|  h  |  t  |  t  |  p  |  :  |  /  |  /  |     . . .     |  ? |
+-----+-----+-----+-----+-----+-----+-----+----       ----+----+

                              +----------+
                              |    dp    |
                              +----------+
                                   |
                                   | 
                                   V
        +-----+-----+-----+-----+-----+-----+-----+----       ----+----+
scheme[ |  h  |  t  |  t  |  p  |  \0 |     |     |     . . .     |    | ]
        +-----+-----+-----+-----+-----+-----+-----+----       ----+----+

puts (scheme) will work because it still refers to the base of the array
puts (dp) will not work because it does not point to the base of the array
         and currently points to a location pointing to null character

在您上面评论的解决方案中,您可以使用scheme数组来打印字符串。 scheme指的是要打印的数组,scheme指的是数组的基址,因为您尚未对其进行修改(并且无法修改)。这就是它从基数开始并打印到循环后分配的'\0'的原因。

你可以做

 int i;
 for (i=0; (src[i] != ':') && (src[i] != '\0'); i++)
 {
    dp[i] = src[i];
 }

或执行以下操作

 char *dp_bak;
 char *dp = malloc(10);
 dp_bak = dp; /* Backup the base address */

 while (*src != ':')
 {
     *dp = *src;
     src++;
     dp++;
 }
 *dp = '\0';
 dp = db_bak; /* Restore the base address */

 puts (dp);

答案 3 :(得分:-2)

的确,如上所述,“scheme”是指向字符串开头的指针,dp是你的迭代器。

char * scheme = malloc(10),* dp = scheme;

...

放(方案);