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

问题描述

| 我是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);
}
预期的输出为stdout的
http
在这两种情况下,“ 2”应该是指向字符指针“ 3”的数组的指针。但是,使用
malloc
方法时,它什么也不打印。我通过GDB运行代码,我的
src
dp
一次被擦除了1个字符。如果我将
while
循环包含在一个函数调用中,则它将起作用。我发现原因是因为参数被评估为副本。但是,然后我读到数组是异常,并作为指针传递。现在我很困惑。我可以解决此问题,但是我试图理解为什么这种方式行不通。     

解决方法

        您正在循环中更改
dp
dp = malloc(10);
假设
dp
的值为
0x42000000
while () {
    dp++;
}
假设循环进行了4次,所以
dp
的值为
0x42000004
*dp = 0;
现在您在由ѭ2指向的地址处放置一个空字符
puts(dp);
然后尝试打印该null :) 保存
dp
并打印保存的值
dp = malloc(10);
saveddp = dp;
/* ... */
puts(saveddp);
free(saveddp); /* for completeness */
它可以与
scheme
一起使用,因为
scheme
是一个数组,您不能更改该地址!     ,        循环结束后,“ 2”指向分配的字符串的末尾。您需要在
malloc
之后立即保存
dp
并递增副本,而不是指向开头的原始指针。     ,        在循环开始之前,“ 2”指向您已分配内存的开始。在每次迭代中,您将
src
指向的字符复制到pointed2ѭ当前指向的位置,并向前移动step2ѭ指向的一个存储位置。循环结束时,
dp
指向您已分配
\'\\0\'
的字符
p
之后的存储位置。当您尝试用
puts (dp)
打印字符串时,由于ѭ2right的内容已更改,并且现在指向最后一个复制的字符之后的位置,它将从该位置开始打印。它将打印一个空字符串,因为
dp
指向的第一个位置是一个空字符。 循环前
+----------+
|   src    |
+----------+
   |
   | 
   V
+-----+-----+-----+-----+-----+-----+-----+----       ----+----+
|  h  |  t  |  t  |  p  |  :  |  /  |  /  |     . . .   ? |  ? |
+-----+-----+-----+-----+-----+-----+-----+----       ----+----+

+----------+
|    dp    |
+----------+
   |
   | 
   V
+-----+-----+-----+-----+-----+-----+-----+----       ----+----+
|     |     |     |     |     |     |     |     . . .     |    |
+-----+-----+-----+-----+-----+-----+-----+----       ----+----+
After循环(dp = malloc(10))
                      +----------+
                      |   src    |
                      +----------+
                           |
                           | 
                           V
+-----+-----+-----+-----+-----+-----+-----+----       ----+----+
|  h  |  t  |  t  |  p  |  :  |  /  |  /  |     . . .     |  ? |
+-----+-----+-----+-----+-----+-----+-----+----       ----+----+

                      +----------+
                      |    dp    |
                      +----------+
                           |
                           | 
                           V
+-----+-----+-----+-----+-----+-----+-----+----       ----+----+
|  h  |  t  |  t  |  p  |  \\0 |     |     |     . . .     |    |
+-----+-----+-----+-----+-----+-----+-----+----       ----+----+
注意
puts (dp)
将从上面指出的位置开始打印打印。 这不会获得预期的输出。另外,因为您尚未保存 您实际分配的
dp
的原始地址。你不能 在循环后恢复它。 After循环(dp =&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);
    ,        实际上,如上所述,\“ scheme \”是您指向字符串开头的指针,而dp是您的迭代器。 char * scheme = malloc(10),* dp = scheme; ... 放置(方案);