【问题标题】:%d pointer-to-integer conversion in C strings?C 字符串中的 %d 指针到整数的转换?
【发布时间】:2025-11-21 17:50:01
【问题描述】:

通过查看此代码示例:

/* strrchr example */
#include <stdio.h>
#include <string.h>

int main ()
{
  char str[] = "This is a sample string";
  char * pch;
  pch=strrchr(str,'s');
  printf ("Last occurence of 's' found at %d \n",pch-str+1);
  printf("pch number: %d \n str number: %d", pch, str);
  return 0;
}

输出如下:

Last occurence of 's' found at 18 
pch number: -8575 
str number: -8592

我不明白,pchstr 有什么数字,printf() 中的 %d 下似乎有什么转换。这是否类似于内存单元的编号,指向第一个字符的指针所在的位置(在str 的情况下)?如果是这样,为什么strpch 大?它应该代表指向第一个字符串字符的指针,不是吗?最后,为什么我们在pch-str+1 中需要+1

补充:这不是我的代码(第二个printf() 除外)。我在cplusplus.com 上找到它,正在寻找strrchr() 参考。

【问题讨论】:

  • 始终注意编译器警告。 pchstr 是指针。使用%p 格式化指针。并且str 指针值大于pch。它“更负”,因此值更小。
  • “最后,为什么我们在 pch-str+1 中需要 +1?” - 你不需要它。尝试使用和不使用它并观察差异。
  • 如果有任何答案适合您,您可能想给他们投票。您还应该接受最能涵盖您的答案(按答案左侧的绿色勾号 - 您只能接受一个答案)。
  • “这是否类似于内存单元的编号,指向第一个字符的指针所在的位置(在 str 的情况下)?如果是这样,为什么 str 大于 pch?” --> 就像问为什么你的家庭地址比你朋友的家庭地址大,即使你住在同一条街上。

标签: c string pointers integer


【解决方案1】:

pch 和 str 是指针。它们包含您的字符串内存中的地址和最后一个 s 字符。 (这就是为什么它们相差 18)

您没有正确打印它们,因此您没有看到完整的地址。执行 %p 而不是 %d (告诉编译器这些是指针)

pch - str + 1 有效,因为您可以添加和减去地址。它们只是非常大的数字,但是当您减去它们时,您可以得到小数字(100001 - 100000 = 1)。编译器知道它们是指针,所以“做正确的事”。为什么没有 printf '做正确的事情'?,因为 printf 的工作方式是在程序运行时使用 %d,编译器不知道发生了什么。实际上那是个谎言,大多数现代编译器都知道 printf 的行为,并且会查看格式字符串以查看其是否正常。如果您正确设置编译器选项,它将警告您对指针执行 %d

【讨论】:

  • 我对指针有一定的了解(至少我是这么认为的)。我理解我尝试在%d 中打印它们的错误。所以,pch-str+1 的行对我来说仍然是遥不可及的。是否类似于指针算术(根据另一个答案判断)以及转换为十进制表示法?为什么,仍然,str 指向结尾,为什么我需要使用+1?当然,要使它正确,但是为什么呢? str 指向第一个(什么?字节?字符?null?)比有效的字符串字符(似乎是'\0?)更远?
【解决方案2】:

strpch 不单独存储值;它们指向内存中的某个地方,因此它们的值实际上是它们指向的内存中的地址。

在计算机科学中,指针是一种编程语言对象,其值使用其地址引用(或“指向”)存储在计算机内存中其他位置的另一个值。指针引用一个位置在内存中,获取存储在该位置的值称为取消引用指针。打个比方,一本书的索引中的页码可以被认为是指向相应页面的指针;取消引用此类指针将通过翻转到具有给定页码的页面来完成。

Wikipedia

结果绝对自然:要对此进行测试,您必须了解 2 的补码是如何工作的:让我们以 wikipedia 提供的这个示例为例:

Binary Unsigned 2's complement
011     3       3 
010     2       2 
001     1       1 
000     0       0 
111     7       -1 
110     6       -2 
101     5       -3 
100     4       -4 

我想通过这个告诉你,最大的无符号二进制值被映射到 2 的补码中的最大负值。

要解决此问题,请按如下方式更改您的程序:

/* strrchr example */
#include <stdio.h>
#include <string.h>

int main ()
{
  char str[] = "This is a sample string";
  char * pch;
  pch=strrchr(str,'s');
  printf ("Last occurence of 's' found at %ld \n",pch-str+1);
  printf("pch number: %ld \n str number: %ld", pch, str);
  return 0;
}

您需要做的唯一更改是将%d 更改为%ld,因此程序将打印long int 值而不是int 值。

当我测试这段代码时,我得到:

Last occurence of 's' found at 18 
pch number: 140735717807905 
str number: 140735717807888

但是,最典型和最正确的打印指针的方法是使用 %p。

/* strrchr example */
#include <stdio.h>
#include <string.h>

int main ()
{
  char str[] = "This is a sample string";
  char * pch;
  pch=strrchr(str,'s');
  printf ("Last occurence of 's' found at %p \n",pch-str+1);
  printf("pch number: %p \n str number: %p", pch, str);
  return 0;
}

哪些打印:

Last occurence of 's' found at 0x12 
pch number: 0x7fffdcf2b3f1 
str number: 0x7fffdcf2b3e0

回答你的最后一个问题:

最后,为什么我们在 pch-str+1 中需要 +1?

让我们看一个例子:

strings
1-----7 

所以我们假设 pch 等于 7 并且 str 等于 1。pch - str 将产生 6 作为结果,所以我们需要增加该值以显示最后一个 s 的位置。

【讨论】:

  • 这并不能解释 pch 和 str 是指针的事实;只是比整数大的事实
  • 感谢您的长篇回答,也将阅读更多关于二进制补码的内容。
【解决方案3】:

您的代码会导致未定义的行为。 printf 函数不是“魔术”:它不知道您传入的参数类型是什么。您有责任提供正确的格式说明符,然后 printf 函数将知道在哪里在内存中查看以及读取多少字节以获得该格式的值。

如果你做了不匹配,那么任何事情都可能发生,函数读取错误的区域,你得到的垃圾可能与你传入的值完全无关(或者其他任何事情也可能发生)。

在您的代码中,匹配格式说明符将是:"%td" 对应 pch - str + 1"%s" 对应 pch"%s" 对应 str。虽然我不清楚您希望在第二行打印什么。

【讨论】:

  • 我希望了解strpch 代表什么以及这个神奇的pch-str+1 是如何工作的。为什么会有这些数字,为什么会有这种差异以及为什么有+1。此外,此代码来自cplusplus.com,但没有第二个printf()
  • @AlexeyVilchansky pch - str 并不神奇。减去两个指针得到一个整数,它是这两个指针之间的元素数。给一个整数加 1 给出下一个最大的整数。你也没有在你的问题中问这个问题,所以也许更新你的问题来问这个问题。
  • str 是一个字符数组,ptr 是一个指向字符的指针。正如我的回答所解释的那样,对它们使用 %d 会导致未定义的行为
【解决方案4】:

pch 是字符串中最后一个s 的地址。 str 是字符串开头的地址。 pch-strstrpch之间的字节数,也就是s在字符串中的位置。您添加 1 是因为您希望结果是从 1 开始的,就像正常人认为的那样,而不是像计算机认为的那样从 0 开始(所以如果 s 是第一个字符,它将显示 found at 1,而不是 @ 987654331@).

正如其他人所说,打印pchstr 时得到奇怪值的原因是因为您使用了错误的printf 格式运算符。您应该使用%p 来打印指针。

【讨论】:

  • 感谢您的回答!使用%p 似乎pch 大于str 并且减法很好。 +1 现在也很清楚了。我对第一个printf() 语句中的%d 转换感到尴尬。据我了解,指针减法继续进行,然后转换为整数。
【解决方案5】:

“这是否类似于内存单元的编号,指向第一个字符的指针所在的位置(在 str 的情况下)?如果是这样,为什么 str 比 pch 大?” --> 就像问为什么你的家庭地址比你朋友的家庭地址大,即使你住在同一条街上。有简单的地址。

pch - str + 1 中的 +1 可能是因为作者喜欢从 1 开始计算字符串中的位置。在 C 中从 0 开始更习惯用语,因此:pch - str

使用匹配的修饰符/说明符。

char str[] = "This is a sample string";
char * pch;
pch = strrchr(str,'s');

// pointer subtraction results in type `ptrdiff_t`.  Use `t`
printf("Last occurrence of 's' found at %td \n", pch - str);

// Use p and add cast to `void *`
printf("pch number: %p \n str number: %p", (void *) pch, (void *) str);

【讨论】: