开发者

C char pointer vs pointer to char array, increment dynamic allocation

I am new to C, and I am having difficulty understanding the reason why the block of code below is not working.

#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
开发者_C百科       puts(scheme)
     */

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

The expected output is http to stdout. In both cases dp should be a pointer to an array of char pointers (char **). However it is printing nothing when using malloc method. I ran the code through GDB and my src and dp are getting erased 1 character at a time. If I enclose the while loop into a function call it works. I figured that the reason was because parameters are evaluated as a copy. However, then I read that arrays are the exception and passed as pointers. Now I am confused. I can work around this, but I am trying to understand why this way doesn't work.


You are changing dp inside the loop

dp = malloc(10);

let's say dp has the value 0x42000000

while () {
    dp++;
}

let's say the loop went 4 times, so dp has the value 0x42000004

*dp = 0;

now you put a null character at the address pointed to by dp

puts(dp);

and then you try to print that null :)

Save dp and print the saved value

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

It works with scheme because scheme is an array and you cannot change that address!


After the end of the loop, dp points to the end of the allocated string. You need to save dp right after the malloc and increment the copy, not the original pointer to the beginning.


Before the loop starts the dp points to the start of the memory you have allocated. At each iteration you copy the character pointed by src into the currently pointed location of dp and step forward one memory location pointed by dp. At the end of the loop dp is pointing at the memory location right after the character p where you have assigned a '\0'. When you attempt to print the string with puts (dp) because the contents of dp has changed and now points to a location right after the last character copied, it will start printing from that location. It will print an empty string as the very first location pointed by dp is a null character.

Before Loop

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

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

After Loop (with dp = malloc (10))

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

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

Note puts (dp) will start printing print from the location pointed above. This will not get the intended output. Also because you have not saved the original address of dp which you have actually allocated. You are not able to restore it after the loop.

After Loop (with 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

In the above commented solution of yours works because, you use the scheme array to print the string. scheme refers to the array you want to print and scheme refers to the base address of the array because you have not modified it (and it cannot be modified). This is why it starts from the base and prints upto the '\0' you have assigned after the loop.

You can either do

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

or do the below

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


Indeed, as pointed out above, "scheme" was your pointer to the beginning of the string, and dp was your iterator.

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

...

puts(scheme);

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜