我是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运行代码,我的src
和dp
一次被删除1个字符。如果我将while
循环包含在函数调用中,它就可以工作。我认为原因是因为参数被评估为副本。但是,我读到数组是异常并作为指针传递。现在我很困惑。我可以解决这个问题,但我试图理解为什么这种方式不起作用。
答案 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
+-----+-----+-----+-----+-----+-----+-----+---- ----+----+
| | | | | | | | . . . | |
+-----+-----+-----+-----+-----+-----+-----+---- ----+----+
+----------+
| src |
+----------+
|
|
V
+-----+-----+-----+-----+-----+-----+-----+---- ----+----+
| h | t | t | p | : | / | / | . . . | ? |
+-----+-----+-----+-----+-----+-----+-----+---- ----+----+
+----------+
| dp |
+----------+
|
|
V
+-----+-----+-----+-----+-----+-----+-----+---- ----+----+
| h | t | t | p | \0 | | | . . . | |
+-----+-----+-----+-----+-----+-----+-----+---- ----+----+
注意puts (dp)
将从上面指出的位置开始打印。
这不会得到预期的输出。还因为你没有保存过
您实际分配的dp
的原始地址。你不能
在循环之后恢复它。
+----------+
| 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;
...
放(方案);