【问题标题】:C error expected ‘char **’ but argument is of type ‘char (*)[10]’C 错误应为“char **”,但参数类型为“char (*)[10]”
【发布时间】:2021-09-18 16:58:25
【问题描述】:

我正在尝试实现我的strcat 版本。但是,我收到以下警告,并且我的代码在运行时崩溃。我从 main 传递 &p 以对 main 函数中的变量 p 进行永久更改。

警告:

note: expected ‘char **’ but argument is of type ‘char (*)[10]’

代码:

#include<string.h>
#include<stdio.h>

void mystrcat(char **p, char *q)
{
    while(**p != '\0')
    {
        *p++;
    }

    while(*q != '\0')
    {
        **p = *q;
        (*p)++;
        q++;
    }
    *p = '\0';

}

int main()
{
    char p[10]="ravi";
    char q[12]="ra";

    mystrcat(&p, q);
    printf("%s", p);
}

【问题讨论】:

  • 试试char *p="ravi";
  • @tstanisl 那将是 UB。
  • 不,我不能改变 char p[10]="ravi";这不是我想要的,因为我希望我的程序在任何情况下都可以运行,即使给出的是 char 数组而不是指向 char 的指针
  • 也许好的第一步是查看标准strcat 的接口。它在某处有char ** 吗?为什么你认为你需要一个?
  • 您是否也打算将它与动态分配的数组一起使用?这就是为什么第一个参数是char**,以便能够修改该指针的原因吗?如果是这种情况,您还应该传递分配的大小,否则不需要传递指向指针的指针。

标签: c pointers c-strings strcat function-definition


【解决方案1】:

而不是指向char的指针,只需传递一个指向char的指针,它也会使修改永久化。这就是string.h strcat 的工作原理。也许还检查 NULL 指针。

#include <stdio.h>
#include <stdlib.h>

char *mystrcat(char *p, char *q)
{
    char *ptr = p; /* so you dont alter p's initial address */

    if (p == NULL || q == NULL)
    {
        exit(EXIT_FAILURE);
    }

    while(*ptr != '\0')
    {
        ptr++;
    }

    while(*q != '\0')
    {
        *ptr = *q;
        ptr++; /* you dont have to dereference */
        q++;
    }
    *ptr = '\0';

    return p;
}

int main(void)
{
    char p[100]="hello";
    char q[12]="world";

    mystrcat(p, q);
    printf("%s", p);

    return 0;
}

【讨论】:

  • 我很惊讶为什么我不需要指向 char 的指针来使更改永久化。想一个场景,你想永久地交换一个函数中的两个变量,你必须传递它的地址,那么为什么不在这种情况下呢?
  • char *ptr = p; /* so you dont alter p's initial address , in case of a dynamic string */ 没有意义,mystrcat 中的p 已经是mainp 的副本(衰减为指针)。无需制作额外的副本。
  • @Ravi char *p 实际上是在传递字符串中字符的地址
  • @mch 是的,您确实是对的,我忘记将返回类型更改为 char *。已编辑。
  • @alex01011 我仍然认为这条线没有任何理由。只需将其删除并使用 p 而不是 ptr 即可完成相同的操作。
【解决方案2】:

变量p被声明为具有char[10]类型

char p[10]="ravi";

所以这个调用中的表达式&amp;p

mystrcat(&p, q);

类型为char ( * )[10]

但是对应的函数参数的类型为char **

void mystrcat(char **p, char *q)

并且没有从char ( * )[10]类型到char **类型的隐式转换,所以编译器会报错。

您可以通过以下方式调用您的函数

char *tmp = p;
mystrcat( &tmp, q );

但无论如何,至少由于这个while循环,函数是不正确的

while(**p != '\0')
{
    *p++;
}

因为表达式

*p++

等价于表达式

*( p++ )

当你需要表达时

( *p )++

++*p

或者最后一条语句应该是

**p = '\0';

而不是

*p = '\0';

将第一个函数参数声明为具有 chat ** 类型而不是在标准 C 函数 strcat 中声明的类型 char * 是没有任何意义的。

char * strcat(char * restrict s1, const char * restrict s2);

此外,第二个参数应具有限定符const,因为相应的字符串不会在函数内更改。该函数应该返回一个指向目标字符串的指针。

所以函数可以如下所示

char * mystrcat( char *p, const char *q )
{
    char *s = p;

    while ( *s ) ++s;

    while ( ( *s++ = *q ) != '\0' ) ++q;

    return p;
}

并被称为

puts( mystrcat( p, q ) );

这是一个演示程序。

#include <stdio.h>

char * mystrcat( char *p, const char *q )
{
    char *s = p;

    while ( *s ) ++s;

    while ( ( *s++ = *q ) != '\0' ) ++q;

    return p;
}

int main(void) 
{
    char p[10] = "ravi";
    char q[12] = "ra";
    
    puts( mystrcat( p, q ) );
    
    return 0;
}

程序输出是

ravira

【讨论】:

    【解决方案3】:

    您需要传递一个指向数组中每个单独字符的指针:

    int main()
    {
     char p[10]="ravi5";
     char q[12]="ra54";
     
     char* pPointer = p;
     char** pPointerPointer = &pPointer;
    
     mystrcat(pPointerPointer, q);
     printf("%s", p);
     return 0;
    }
    

    注意:在您的 strcat 函数中,您错过了括号:

    while(**p != '\0')
    {
     (*p)++;
    }
    

    【讨论】:

      猜你喜欢
      • 2023-04-08
      • 2016-09-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-21
      • 2019-12-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多