Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/.htaccess/5.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
C 如何理解复杂的函数声明?_C_Pointers_Declaration - Fatal编程技术网

C 如何理解复杂的函数声明?

C 如何理解复杂的函数声明?,c,pointers,declaration,C,Pointers,Declaration,我如何理解以下复杂的声明 char (*(*f())[])(); char (*(*X[3])())[5]; void (*f)(int,void (*)()); char far *far *ptr; typedef void (*pfun)(int,float); int **(*f)(int**,int**(*)(int **,int **)); 听起来像是cdecl工具的工作: cdecl> explain char (*(*f())[])(); declare f

我如何理解以下复杂的声明

char (*(*f())[])();

char (*(*X[3])())[5];

void (*f)(int,void (*)()); 

char far *far *ptr;

typedef void (*pfun)(int,float);

int **(*f)(int**,int**(*)(int **,int **));

听起来像是cdecl工具的工作:

cdecl> explain char (*(*f())[])();
declare f as function returning pointer to array of pointer to function returning char
我四处寻找这个工具的官方主页,但找不到一个看起来是真的。在Linux中,您通常可以期望您选择的发行版包含该工具,因此我只是安装了它以生成上面的示例。

您应该使用该工具。它应该可以在大多数Linux发行版上使用

e、 g.对于此函数,它将返回您:

char(*(*f())[])()-将f声明为函数返回指针到函数返回字符的指针数组

void(*f)(int,void(*)()-函数指针f的原型。f是一个接受两个参数的函数,第一个参数是int,第二个参数是返回void的函数的函数指针

char far*far*ptr-ptr指向一个远指针(指向某个字符/字节)

char(**X[3])()[5]-X是一个包含3个指针的数组,指向接受数量不确定的参数并返回指向5个字符数组的指针的函数

typedef void(*pfun)(int,float)-声明函数指针pfun。pfun是一个函数,它有两个参数,第一个是int,第二个是float类型。函数没有返回值

e、 g

顺便说一句,最后一个复杂的声明并不常见。这是我为这个目的刚刚编的一个例子

int **(*f)(int**,int**(*)(int **,int **));

typedef int**(*fptr)(int **,int **);

int** f0(int **a0, int **a1)
{
    printf("Complicated declarations and meaningless example!\n");
    return a0;
}

int ** f1(int ** a2, fptr afptr)
{
    return afptr(a2, 0);
}

int main()
{
    int a3 = 5;
    int * pa3 = &a3;
    f = f1;
    f(&pa3, f0);

    return 0;
}
这是一个过时的Microsoft表单,可以追溯到MS-DOS和很早的Windows时代。简短的版本是,这是指向字符的远指针,远指针可以指向内存中的任何位置,而近指针只能指向64K数据段中的任何位置。你真的不想知道微软内存模型的细节,因为它可以解决完全死气沉沉的英特尔80x86分段内存体系结构

typedef void (*pfun)(int,float);
这将pfun声明为指向接受int和float的过程的指针的typedef。 您通常会在函数声明或原型中使用它,即

float foo_meister(pfun rabbitfun)
{
  rabbitfun(69, 2.47);
}

正如其他人所指出的,cdecl是这项工作的正确工具

如果您想在没有cdecl帮助的情况下理解这种声明,请尝试从内到外和从右到左阅读

从您的列表
char(*(*X[3])()[5]中随机抽取一个示例
从X开始,X是要声明/定义的标识符(以及最里面的标识符):

X是

X是3的数组

X是一个由3个指针组成的数组,指向

X是一个包含3个指针的数组,指向接受未指定(但固定)数量的参数的函数

X是一个包含3个指针的数组,指向接受未指定(但固定)数量的参数并返回指针的函数

X是一个包含3个指针的数组,指向接受未指定(但固定)数量的参数并返回指向5个数组的指针的函数


X是一个包含3个指针的数组,指向接受未指定(但固定)数量的参数的函数,并返回指向5个字符数组的指针。

忘记1和2吧-这只是理论上的


3:这用于程序输入函数
int main(int argc,char**argv)
。您可以使用
char**
访问字符串列表。argv[0]=第一个字符串,argv[1]=第二个字符串,…

Remo.D对读取函数的回答是一个很好的建议。以下是其他问题的一些答案

指向指针的指针的一个用例是当您希望将其传递给将修改指针的函数时。例如:

void foo(char **str, int len)
{
   *str = malloc(len);
}
typedef void foofun(char**, int);
foofun *foofunptr;
此外,这可能是一个字符串数组:

void bar(char **strarray, int num)
{
   int i;
   for (i = 0; i < num; i++)
     printf("%s\n", strarray[i]);
}
或者,对于“返回char函数指针数组[]的函数返回指针”的第一个示例,您可以执行以下操作:

typedef char fun_returning_char();
typedef fun_returning_char *ptr_to_fun;
typedef ptr_to_fun array_of_ptrs_to_fun[];
typedef array_of_ptrs_to_fun *ptr_to_array;
ptr_to_array myfun() { /*...*/ }
实际上,如果你写的东西是理智的,那么其中很多东西都会有自己有意义的名字;例如,这些函数可能是返回名称(某种类型)的函数,因此
fun\u returning\u char
可以是
name\u generator\u type
,而
数组\u of ptr\u to\u fun
可以是
name\u generator\u list
。因此,您可以将它折叠几行,只定义这两个typedef——这在任何情况下都可能在其他地方有用

x:返回指向的指针的函数 函数指针的数组[] 回来了,嗯

你有一个功能

该函数返回一个指针

该指针指向一个数组

该数组是函数指针(或函数指针)的数组

这些函数返回char*

 what's the use case for a pointer to a pointer?
一种是通过参数方便返回值

假设你有

int function(int *p)
  *p = 123;
   return 0; //success !
}
你把它叫做

int x;
function(&x);
char *x;
function(&x); 
如您所见,要使
函数
能够修改我们的
x
,我们必须向它传递一个指向x的指针

如果
x
不是一个int,而是一个
char*
,那该怎么办?好吧,它还是一样的,我们必须传递一个指向它的指针。指向指针的指针:

int function(char **p)
  *p = "Hello";
   return 0; //success !
}
你把它叫做

int x;
function(&x);
char *x;
function(&x); 

从内部读出来,类似于你求解方程的方式,比如
{3+5*[2+3*(x+6*2)]}=0
——你首先要求解内部的内容
()
,然后
[]
,最后
{}

char (*(*x())[])()
         ^
这意味着
x
某种东西

char (*(*x())[])()
          ^^
char (*(*x())[])()
        ^
char (*(*x())[])()
       ^    ^^^
char (*(*x())[])()
      ^
char (*(*x())[])()
     ^         ^^^
x
是一个函数

char (*(*x())[])()
          ^^
char (*(*x())[])()
        ^
char (*(*x())[])()
       ^    ^^^
char (*(*x())[])()
      ^
char (*(*x())[])()
     ^         ^^^
x
返回指向某个对象的指针

char (*(*x())[])()
          ^^
char (*(*x())[])()
        ^
char (*(*x())[])()
       ^    ^^^
char (*(*x())[])()
      ^
char (*(*x())[])()
     ^         ^^^
x
返回指向数组的指针

char (*(*x())[])()
          ^^
char (*(*x())[])()
        ^
char (*(*x())[])()
       ^    ^^^
char (*(*x())[])()
      ^
char (*(*x())[])()
     ^         ^^^
x
返回指向指针数组的指针

char (*(*x())[])()
          ^^
char (*(*x())[])()
        ^
char (*(*x())[])()
       ^    ^^^
char (*(*x())[])()
      ^
char (*(*x())[])()
     ^         ^^^
x
返回指向函数指针数组的指针

char (*(*x())[])()
^^^^
这意味着
x
返回的数组指针指向函数指针数组,这些函数指针指向返回字符的函数

char (*(*x())[])()
          ^^
char (*(*x())[])()
        ^
char (*(*x())[])()
       ^    ^^^
char (*(*x())[])()
      ^
char (*(*x())[])()
     ^         ^^^
但是,是的,用它。我自己用它来检查我的答案:)

如果这仍然是