当前位置:  开发笔记 > 编程语言 > 正文

当我应该而且不应该在C中使用"const"时感到困惑

如何解决《当我应该而且不应该在C中使用"const"时感到困惑》经验,为你挑选了2个好方法。

我有一个字典,如下所示:

typedef struct dictNode {
    int key;
    char *value;
    struct dictNode *next;
} Dict;

get()函数是这样的:

char *get(const Dict *dict, int key) {
    if(!dict) return NULL;

    Dict *currPtr = dict;

    while(currPtr) {
        if(currPtr->key == key) {
            return currPtr->value;
        }

        currPtr = currPtr->next;
    }
}

编译此代码会产生以下错误:
dict.c:85:warning:initialization从指针目标类型中丢弃限定符

此警告涉及以下行:

Dict *currPtr = dict;

如果我在该行之前添加"const",如下所示:

const Dict *currPtr = dict;

警告消失了......

1)我不明白的第一件事就是:我在get()中dict参数中添加了"const",这样编译器会在我尝试更改dict指向的地址时警告我,否则我将无法访问主程序中的字典导致我丢失了我指向的地址.现在,我正在创建一个新指针currPtr,它指向与dict相同的位置.这样,我使用这个指针来遍历字典并保持dict指针不变.为什么我还需要constcurrPtr

2)我不明白的第二件事是:线currPtr = currPtr-> next; 正在改变currPtr指针,所以,如果我向currPtr添加一个const,为什么编译器不会警告我?

然后我有一个del()函数,如下所示:

Dict *del(const Dict *dict, int key) {
    if(!dict) return NULL;

    Dict *currPtr = dict;
    Dict *prevPtr = dict;

    while(currPtr) {
        if(currPtr->key == key) {
            prevPtr->next = currPtr->next;
            free(currPtr);
        }

        prevPtr = currPtr;
        currPtr = currPtr->next;
    }

    return dict;
}

请注意,我知道这个删除功能代码不完整,如果我想删除第一个元素,它就无法正常工作.没关系,我稍后会说完,这足以证明我的问题......

3)所以,在get()函数中我需要将const添加到currPtr但是在这个del()函数中,我不需要将const添加到currPtrprevPtr?在这两个函数中,我正在更改currPtr指针,在del()函数的情况下,我也在更改prevPtr指针.为什么get()函数要求我在currPtr之前添加一个const,而del()函数不要求我在currPtrprevPtr之前添加一个const

我基本上可以恢复这个帖子:我的get()del()函数的确切时间和地点应该使用const和为什么,以及何时何地我不应该?



1> Johannes Sch..:

没有指针,你会有

const Dict currPtr

这是一个不变的Dict.现在,如果你把它作为你的指针

const Dict *currPtr

这是一个指向常量Dict的指针.这并不意味着指针是常量.但这确实意味着Dict指出被视为不变

currPtr->key = 10; // error, dict is treated as constant. 

但指针不是

currPtr = otherPtr; // possible: the pointer is not constant

如果使指针保持不变,则第二种情况会出错.保持指向的dict也不变,这看起来像这样

const Dict * const currPtr = init;

现在你不能将currPtr设置为指向不同的东西,因为指针现在是常量,而不仅仅是指针所指向的那样.有些人喜欢看看const是否总是正确的东西,它使const.这看起来像这样

Dict const * const currPtr = init;

这与前一个片段相同.如果你从右到左阅读它,它会告诉你它是什么"const指向const Dict的指针".如果您有类型,则无论您如何订购说明符

int const a = 10;
const int b = 10;

两者都是常数整数.这就是为什么我们可以把const放在Dict类型说明符的右边.

现在,如果你有一个指针,你总是可以假装你指向一个常量对象,即使该对象没有被声明为const.但是,如果您指向的是const对象,则不能假装使用非const对象:

int const *p = NULL;
// doesn't work without a cast. Will at least provoke a warning
int *pn = p;

int *p = NULL;
// always works: pretending to point to something const doesn't harm.
int const *pc = p;

请注意,如果将指针本身设为const,则规则与此不同.它们类似于应用于其他类型的const:

int const i = 0;
int j = i; // works. we only read the value of i. its const doesn't matter. 

int * const p = NULL;
int * q = p; // works: we only read the value of p (a null pointer).

将值复制到新变量(无论是否为指针)后,新变量不会以任何方式连接到另一个变量,因为读取的值与首先创建值的方式没有关联.另一个变量的const无关紧要.



2> Steve Jessop..:

"我在get()中的dict参数中添加了"const",以便编译器在我尝试更改地址时警告我dict指向"

在那种情况下,你意味着Dict *const dict,而不是const Dict *dict.您已将结构声明为const,而不是指向它的指针.

"为什么我还需要为currPtr使用const"

因为否则你可以使用currPtr来修改字典结构本身,它应该是这个函数中的const.

"行currPtr = currPtr-> next;正在改变currPtr指针,所以,如果我向currPtr添加了一个const,为什么编译器不会警告我?"

同样的原因:如果const位于你放置它的位置,那不是错误.如果const是在currPtr的另一个地方的话.

否则我将无法访问主程序中的字典,因为我丢失了我指向的地址

否 - 当主程序调用get时,它将指针值传递给例程,这将成为get函数中dict的值.但是get有自己的指针变量,与主程序中的变量分开.即使它们恰好都被称为"dict",改变一个指针也不会改变另一个指针.

两个变量都指向相同的结构,因此如果您使用该变量来修改结构中的任何字段,那么结果当然会影响两个代码位.通常,一个名为"get"的函数将是一个只读操作,因此您创建参数是正确的const Dict *.但我认为这是正确的,与你的想法略有不同.这是为了保护字典的内容不被改变,而不是保护你的地址记录.

但是,对于像这样的链接列表,const-safety有点尴尬.即使你有一个const Dict,它的"next"字段仍然不指向const.因此,尽管您无法修改第一个节点,但const-system不会保护您不会修改列表中的其他节点.C++通过函数重载来解决这个问题,所以你可以有一个"getnext"函数,如果输入是const,则返回const输出,如果输入是非const,则返回非const输出.您可以使用"getnext"和"getnext_c"在C中实现类似的功能,后者具有const参数并返回.但大多数人都不打扰,包括像strchr这样的标准库函数,它在C中采用const char*但返回非const char*.因此,strchr可以在C中意外使用,将const字符串转换为非const字符串,而不会发出任何警告.或故意,在这种情况下,它有点像通过"合法"业务洗钱;-)

del()函数不要求我在currPtr和prevPtr之前添加一个const?

我承认我很难过.我期待与"获取"相同的警告 - 你确定不存在吗?但del的参数无论如何都不应该是const,因为你可能会修改字段.






推荐阅读
echo7111436
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有