【问题标题】:double pointer vs pointer to array, incompatible pointer type双指针与指向数组的指针,不兼容的指针类型
【发布时间】:2020-10-11 10:37:39
【问题描述】:

有这个:

#define _DEFAULT_SOURCE 1
#include <stdio.h>
#include <string.h>

int main(){
    char *token, org[] = "Cats,Dogs,Mice,,,Dwarves,Elves:High,Elves:Wood";
    while((token=strsep(&org,",")))
        printf("Token: %s\n",token);
}

给出错误(不兼容的指针类型):

/usr/include/string.h:439:14: note: expected ‘char ** restrict’ but argument is of type ‘char (*)[47]’
 extern char *strsep (char **__restrict __stringp,
  1. 我知道它是不同的类型(一个已初始化内存 -> org[],但该函数需要没有初始化任何内存的指针),但它们具有相同的行为,所以为什么它仍然抱怨?

  2. 有人可以解释一下,这个关键字restrict__restrict*strsep (char **__restrict __stringp, 的情况下是什么意思(另一方面,我假设__stringp 不是内部数据类型(因为双下划线),但只是一个花哨的变量名)。

编辑: 我认为一个数组存储在堆栈中,但是strsep 想要一个指向堆的指针,这可以通过将org 分配给malloc 然后memcpy 来完成,或者更好的是,复制字符串通过strdup(内部memcpy)。但无论如何,strsep 想要指向堆而不是堆栈的指针吗?两者都只是指针,只指向不同的地址,但这不应该介意。

【问题讨论】:

标签: c arrays pointers memory


【解决方案1】:
#include <stdio.h>
#include <string.h>

int main()
{
    char org[] = "Cats,Dogs,Mice,,,Dwarves,Elves:High,Elves:Wood";
    char *token = strtok(org, ",");
    while (token != NULL) {
        printf("Token: %s\n", token);
        token = strtok(NULL, ",");
    }
}

我认为你应该看看这个页面:Restrict type qualifier

【讨论】:

  • 不,我不想使用 strtok 函数,如果我想用该函数发布问题,请查看我的帖子,我在哪里使用由 @987654325 定义的 strsep @。这是题外话
【解决方案2】:

strsep 函数需要一个 modifiable 指针的地址作为它的第一个参数(或NULL,在这种情况下它什么都不做);您正在将数组的(固定)地址传递给它。您可以通过声明一个单独的char* 变量并将org 数组的(地址)分配给该变量来解决此问题:

int main()
{
    char* token, org[] = "Cats,Dogs,Mice,,,Dwarves,Elves:High,Elves:Wood";
    char* porg = org; // "porg" is a MODIFIABLE pointer initialized with the start address of the "org" array
    while ((token = strsep(&porg, ",")))
        printf("Token: %s\n", token);

    return 0;
}

来自Linux manual page(我的粗体字):

如果*stringpNULL,则strsep() 函数将返回NULL 并执行 没有其他的。否则,此函数在 字符串*stringp,由字符串中的一个字节分隔 delim。通过用 a 覆盖分隔符来终止此标记 空字节 ('\0'),*stringp 被更新为指向过去的令牌。在 如果没有找到分隔符,则将令牌视为整个 字符串*stringp,而*stringp 变成NULL

关于restrict关键字的含义和使用,也许这会有所帮助:Realistic usage of the C99 'restrict' keyword?

【讨论】:

  • 在什么意义上您指的是 fix 地址与 modifiable 地址?两者都只是地址。您的汽车对它们都执行指针算术。你能解释一下,固定地址是什么意思?
  • @milanHrabos org 是在函数中声明的数组(main,在这种情况下,但它可以是 any 函数)。通常,此类数据的内存(称为“自动变量”)在堆栈上分配,因此该数据项的地址在定义它的函数的持续时间内是“固定的”。您无法更改该数据的位置。尽管数组和指针有一些句法相似之处,但它们是一回事。
  • 我只知道传递给函数的参数,它们在函数返回后不再存在,但不知道自动变量。 args 的原因是它们被pushed 到堆栈上(在 x32 上,x64 使用寄存器作为 args),并且在函数结束时,堆栈指针是 added(因此删除了推送的 args)。 org 的情况是这样吗?因为 org 不是函数 main 的参数。在生成的程序集中,我只看到leave 指令,但看不到adding 回栈指针。这意味着我可以从堆栈 main 返回后访问org 地址,这使得它可以移动,而不是固定
  • 我的错,只是阅读stackoverflow.com/questions/29790175/…,其中leave 完全符合我提到的adding,所以现在我明白了,一旦函数返回,org 就不能再访问了。但是无论如何,为什么某些函数需要具有可修改(意味着随时可访问)的指针,当它们被主函数堆栈调用时(它们在主函数内部被调用,因此它们可以访问堆栈),堆访问是多余的
【解决方案3】:

数组的地址引用数组开始的地方,它只有不同的类型——指向数组的指针。它不是指向指针的指针。

    char *token, org[] = "Cats,Dogs,Mice,,,Dwarves,Elves:High,Elves:Wood";
    char *pointer = org;
    while((token=strsep(&pointer,",")))
    /* ... */

您不能将对数组的引用转换为双指针。

restrict 这是一个相当高级的话题。它向编译器承诺,如果指针所引用的对象被修改,则只能通过该指针来访问该对象。它有助于编译器进行代码优化

一般来说,在您精通 C 语言之前,我不希望您使用这个限定词。

【讨论】:

  • so only 如果restrict指针引用的对象被修改,那么指针是唯一的入口吗?否则如何修改它,然后使用引用该对象的指针?您能否举一个最小的例子,它的使用是合适的吗?
猜你喜欢
  • 2011-12-16
  • 2018-10-14
  • 2018-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多