12

所以,我知道 char const *、char * const 和 char const * const 之间的区别。那些是:

char* the_string :我可以更改 the_string 指向的字符,也可以修改它指向的字符。

const char* the_string :我可以更改 the_string 指向的字符,但我不能修改它指向的字符。

char* const the_string :我无法更改 the_string 指向的字符,但我可以修改它指向的字符。

const char* const the_string :我无法更改 the_string 指向的字符,也无法修改它指向的字符。

(来自const char * const 与 const char *?

现在,我的问题是:假设我正在编写一个不会修改传递给它的 C 字符串的函数,例如:

int countA(??? string) {
    int count = 0;
    int i;
    for (i=0; i<strlen(string); i++) {
         if (string[i] == 'A') count++;
    }
    return count;
}

现在,标题应该是什么?

int countA(char const * string); 
int countA(char const * const string);

我的感觉是我应该使用第二个,因为我不会修改指针本身,也不会修改数组的内容。但是当我查看标准函数的标题时,他们使用第一个。例子

char * strcpy ( char * destination, const char * source );

为什么?

(实际上char const *对我来说没有任何意义,因为如果您正在考虑抽象字符串,则要么您没有修改字符串(因此,char const * const因为您没有修改指针,也没有修改内容),否则您将修改字符串(所以只是char *因为,你可能会修改内容,你可能需要分配更多的内存,所以你可能需要修改指针)

我希望有人能把这一切告诉我。谢谢。

4

5 回答 5

6

在这种情况下,指针本身是否为 const 并不重要,因为无论如何它都是按值传递的:无论strcpy做什么source都不会影响调用者的变量,因为它将对调用者在堆栈strcpy上的副本进行操作,而不是source原本的。注意我说的是指针值,而不是指针指向的值,显然应该改变它,因为它是参数。

char dest[10];
char const * source = "Hello";
strcpy( dest, source );
// no matter what strcpy does, the value of source will be unchanged

在 内,您需要在由和strcpy指向的数组上迭代指针。不将参数声明为 const 允许函数直接使用堆栈中的值,而无需先复制/强制转换它们。destinationsource

于 2012-07-23T11:27:27.213 回答
5

拥有const char * 代表一个合同。这是一个承诺,该函数不会使用该指针来修改用户传递的内容。指针本身是否为常量的价值较低。

因此,对于调用者来说,指针本身是否const存在没有任何区别。

在许多实现中,“字符串”函数定期修改传递的指针而不修改内容。如果规范(C 标准)要求指针本身保持不变,那么它将成为所有实现的限制因素,而不会为调用者提供任何好处。


作为旁注,我认为你不应该做所有的事情const,然后按照自己的方式解决它。const如果它觉得功能不应该有理由改变它,那就去做吧。简而言之,不要疯狂,这不是灵丹妙药可能会导致挫败感。

于 2012-07-23T11:27:41.230 回答
3

非定义声明:

int countA(char const * string);
int countA(char const * const string);
int countA(char const * foobar);
int countA(char const *);

都是等价的。string参数名称(实际上)是实现内部的一个局部变量countA。实现是否修改该变量与调用者无关,也不影响函数的签名。

函数是否修改 的referand是调用者的事string,所以第一个 const 很重要。变量命名多少是调用者的事,但这只是因为约定是在声明中命名参数作为提示它们的用途。文档是完整传达每个参数含义的方式,而不是其名称。

如果你想要一个规则:省略第二个const,因为它使声明混乱,同时告诉调用者没有任何用处。

您可以将它包含在函数定义中,但这样做会出现一些问题。您要么需要使标头与定义保持同步(在这种情况下,您有时会发现自己更改了标头,因为实现细节的更改不会影响调用者)。否则您必须接受标题与定义不匹配,这有时会使看到以下内容的人感到不安:

int countA(char const * const string) {
    return 0; 
}

并在标题中搜索int countA(char const * const string),反之亦然,查看标题并搜索源。他们需要更智能的搜索词。

于 2012-07-23T11:32:02.663 回答
3

当您将函数参数声明为const char * const时,它与来自 的调用者没有什么不同const char *:他们不在乎您对该指针做什么,因为对他们来说,无论如何这都是“按值传递”。

第二个const是为您服务的,而不是为您的用户服务的。如果您知道您不会修改该指针,那么请务必声明它const char * const:它将帮助您和其他维护您的代码的人在以后捕获错误。

至于标准库,我的猜测是他们不想这样做,const char * const因为他们想要修改指针的能力:

char * strcpy ( char * destination, const char * source ) {
    char *res = destination;
    while (*destination++ = *source++)
        ;
    return res;
}
于 2012-07-23T11:34:13.783 回答
2
  • char const *s:s是指向const char.
  • char *const s:s是一个指向 的常量指针char

Whens是函数参数,第一种表示法比第二种表示法更有用。

  • 使用char const *,您不能修改指向的值。
  • With char *const, you can't modify the value of your pointer. It is like int const in function parameters : you can't do operations directly onto your parameter. It doesn't change anything for the call function. (now, it's almost useless for the compiler, but it's meaningful for programmers)
于 2012-07-23T11:50:39.450 回答