簡體   English   中英

C char 指針與指向 char 數組的指針,遞增動態分配

[英]C char pointer vs pointer to char array, increment dynamic allocation

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

預期的 output 是http到標准輸出。 在這兩種情況下, dp都應該是指向 char 指針數組(char **)的指針。 但是,當使用malloc方法時,它什么也不打印。 我通過 GDB 運行代碼,我的srcdp一次被刪除 1 個字符。 如果我將while循環包含在 function 中,則調用它可以工作。 我認為原因是因為參數被評估為副本。 但是,然后我讀到 arrays 是異常並作為指針傳遞。 現在我很困惑。 我可以解決這個問題,但我試圖理解為什么這種方式行不通。

您正在循環內更改dp

dp = malloc(10);

假設dp的值為0x42000000

while () {
    dp++;
}

假設循環進行了 4 次,所以dp的值為0x42000004

*dp = 0;

現在你把一個 null 字符放在dp指向的地址

puts(dp);

然后你嘗試打印 null :)

保存dp並打印保存的值

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

它適用於scheme ,因為scheme是一個數組,您無法更改該地址!

循環結束后, dp指向分配字符串的結尾。 您需要在malloc之后立即保存dp並增加副本,而不是原始指針指向開頭。

在循環開始之前, dp指向您分配的 memory 的開始。 在每次迭代中,您將src指向的字符復制到dp的當前指向的位置,然后前進一個dp指向的 memory 位置。 在循環的末尾, dp指向 memory 位置,就在您分配了'\0'的字符p之后。 當您嘗試使用puts (dp)打印字符串時,因為dp的內容已更改並且現在指向復制的最后一個字符之后的位置,它將從該位置開始打印。 它將打印一個空字符串,因為dp指向的第一個位置是 null 字符。

循環前

+----------+
|   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)將從上面指出的位置開始打印 print。 這不會得到預期的 output。 也因為你沒有保存你實際分配的dp的原始地址。 您無法在循環后恢復它。

循環后(使用 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;

...

看跌期權(方案);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM