Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/60.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
当我应该和不应该';t使用;常数;在C中_C_Pointers_Constants - Fatal编程技术网

当我应该和不应该';t使用;常数;在C中

当我应该和不应该';t使用;常数;在C中,c,pointers,constants,C,Pointers,Constants,我有一本这样的字典: typedef struct dictNode { int key; char *value; struct dictNode *next; } Dict; char *get(const Dict *dict, int key) { if(!dict) return NULL; Dict *currPtr = dict; while(currPtr) { if(currPtr->key == ke

我有一本这样的字典:

typedef struct dictNode {
    int key;
    char *value;
    struct dictNode *next;
} Dict;
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;
    }
}
const Dict *currPtr = dict;
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;
}
还有一个get()函数,如下所示:

typedef struct dictNode {
    int key;
    char *value;
    struct dictNode *next;
} Dict;
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;
    }
}
const Dict *currPtr = dict;
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;
}
编译此代码会产生以下错误:
dict.c:85:警告:初始化将丢弃指针目标类型中的限定符

此警告涉及以下行:

Dict *currPtr = dict;
如果我在该行之前添加一个“const”,如下所示:

typedef struct dictNode {
    int key;
    char *value;
    struct dictNode *next;
} Dict;
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;
    }
}
const Dict *currPtr = dict;
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;
}
警告消失了

1)我不明白的第一件事是:我在get()中的dict参数中添加了“const”,因此如果我试图更改dict指向的地址,编译器会警告我,否则我将无法访问主程序中的字典,因为我也丢失了指向的地址。现在,我正在创建一个新指针,currPtr,它指向与dict相同的位置。这样,我就使用这个指针来遍历字典并保持dict指针的完整性。为什么currPtr也需要const

2)我不明白的第二件事是:行currPtr=currPtr->next正在更改currPtr指针,因此,如果我将常量添加到currPtr,为什么编译器不警告我这一点

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

typedef struct dictNode {
    int key;
    char *value;
    struct dictNode *next;
} Dict;
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;
    }
}
const Dict *currPtr = dict;
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以及为什么,何时何地不应该使用?

A
const
是一种程序员文档。它告诉您自己,您不会试图修改在
const
qualified中传递的任何内容

您的
get
函数应该采用
const Dict*
,而
del
函数不应该采用。
currPtr
是一个walker——它不会改变
get
Dict
对象的逻辑状态,因此它也应该是
const
限定的。但是,在您的
del
中,它更改了结构,因此这里没有
const

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

在这种情况下,您的意思是
Dict*const-Dict
,而不是
const-Dict*Dict
。您已将结构声明为const,而不是指向它的指针

“为什么我还需要currPtr的常量”

因为否则您可以使用currPtr修改dictionary结构本身,该结构在该函数中应该是const

“currPtr=currPtr->next;行正在更改currPtr指针,因此,如果我在currPtr中添加了一个常量,为什么编译器不警告我这一点?”

同样的原因:如果常量位于您放置它的位置,则它不是一个错误。如果const在另一个地方进行currPtr的话

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

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

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

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

del()函数不要求我在currPtr和prevPtr之前添加常量

const Dict * const currPtr = init;

Dict const * const currPtr = init;
int const a = 10;
const int b = 10;
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;
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).
void list(Dict *dict) {
    if(!dict) return;

    while(dict) {
        printf("KEY: %d\n", dict->key);
        printf("VALUE: %s\n", dict->value);

        dict = dict->next;
    }
}
list(dict);
list(dict);