如何从指针中减去字符数组?

How can a character array be subtracted from a pointer?

所以,我开始熟悉C,此时我正在尝试理解指针。我从 here 获得了以下代码,但我无法理解,如何从指针中减去字符数组。

#include<stdio.h>
#include<string.h>
#include<conio.h>

main() 
{   
char s[30], t[20];   
char *found; 

/* Entering the main string */   
puts("Enter the first string: ");   
gets(s);

/* Entering the string whose position or index to be displayed */   
puts("Enter the string to be searched: ");   
gets(t);

/*Searching string t in string s */   
found=strstr(s,t);   
if(found)
    printf("Second String is found in the First String at %d position.\n",found-s);    
else
    printf("-1");   
getch(); 
}

指针不就是给定variable/constant的地址吗?当减法发生时,字符数组会自动假定,因为操作发生在指针上是减去它的地址?我在这里有点困惑。

提前致谢。

假设您对表达式 found-s 感到疑惑,那么您减去两个指针。

数组自然衰减为指向其第一个元素的指针。这意味着普通 s 等于 &s[0],这就是这里发生的事情:found-s 等于 found - (&s[0]).

并且减法有效,因为 found 指向数组 s 内的一个元素,所以指针是 相关的 (这是对指针减法)。结果是两个指针之间的差异(以元素为单位)。

I cannot comprehend, how does one subtract a character array from a pointer.

从技术上讲,不能。但这并不会使显示的代码无效。

Isn't the pointer only the address of a given variable/constant?

或多或少。指针是地址。有效的是某个对象或函数的地址。

When the subtraction happens the character array automatically assumes that since the operation happens with a pointer is subtracts its address?

关闭。除了少数例外,数组类型的值在表达式中出现的任何地方都被转换为指向第一个数组元素的指针。具体来说:

Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, or is a string literal used to initialize an array, an expression that has type ''array of type'' is converted to an expression with type ''pointer to type'' that points to the initial element of the array object and is not an lvalue.

(C2011, 6.3.2.1/3)

请注意,索引运算符 [] 不在例外之列。索引是一个 pointer 操作。函数调用表达式同样也不例外,因此您实际上不能将数组传递给函数,无论您这样做看起来多么像——相反,您最终传递的是相应的指针。最直接的一点是,差值运算符 - 也不例外,因此有问题的代码表示两个指针之间的差异,而不是数组和指针之间的差异。

C 编译器知道您正在使用的类型及其大小,因此当您进行指针运算时,C 编译器可以为您做一些智能的事情。

例如,如果 int *a = 0x10 那么 a + 1 将给出 0x14 而不是 0x11。编译器知道 int 的大小为 4,因此当您将 1 加到 int 指针的地址时,它会为您提供下一个 int 大小的对象的地址。

同样,当您减去 2 个指针时(即 found - s,编译器不会为您提供两个地址之间的字节数,而是为您提供它们之间的对象数,对于 char (尺寸 1) 是一样的。

一个字符数组不能从一个指针中减去,但一个指针可以从另一个指针中减去,如果两个指针都指向同一数组的元素或指向数组最后一个元素的元素。

来自 C 标准(6.5.6 加法运算符)

9 When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object; the result is the difference of the subscripts of the two array elements. The size of the result is implementation-defined, and its type (a signed integer type) is ptrdiff_t defined in the header. If the result is not representable in an object of that type, the behavior is undefined. In other words, if the expressions P and Q point to, respectively, the i-th and j-th elements of an array object, the expression (P)-(Q) has the value i−j provided the value fits in an object of type ptrdiff_t. Moreover, if the expression P points either to an element of an array object or one past the last element of an array object, and the expression Q points to the last element of the same array object, the expression ((Q)+1)-(P) has the same value as ((Q)-(P))+1 and as -((P)-((Q)+1)), and has the value zero if the expression P points one past the last element of the array object, even though the expression (Q)+1 does not point to an element of the array object.106

那么问题来了:表达式found-s中的s是什么?

C 标准答案(6.3.2.1 左值、数组和函数指示符)

3 Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined.

所以在上面的指向表达式中 s 被转换为指向它的第一个元素的指针,实际上为了清楚起见,表达式可以等效地重写为

found - &s[0]

但是当然知道这种数组指示符到指针的隐式转换更容易编写

found - s

表达式的结果是两个指针之间数组元素的个数。

有时初学者会在对这种转换一无所知的情况下犯下以下错误。他们写例如

char s[] = "Hello";

if ( s == "Hello" )
{
    // ...do something
} 

但是在 if 语句的条件下,不比较存储的字符串。存在数组 s 的第一个元素和字符串文字的第一个元素的比较地址。由于数组和文字占用不同的内存范围,因此条件的结果计算为 false。