【问题标题】:Reverse String with a pointer to a function, which executes the String reverse使用指向函数的指针反转字符串,该函数执行字符串反转
【发布时间】:2020-10-03 22:33:18
【问题描述】:

我想用一个指向函数的指针来反转一个字符串,该函数执行字符串反转。 我感觉我没有正确掌握使用指向变量或函数的指针的概念,所以如果有人能解释我,我会非常感激,我在这里想错了:

1) 定义一个指向函数的指针:

char *strrev(char *str)
{
  char *p1, *p2;

  if (! str || ! *str)
        return str;
  for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2)
  {
      *p1 ^= *p2;
      *p2 ^= *p1;
      *p1 ^= *p2;
   }
   return str;
}

2) 现在我在 main 中定义了一个指针,它与我上面定义的函数相匹配:

int main(void) {

    char (*functPtr)(char);
    functPtr = &strrev;

3) 现在我定义了我要反转的String,定义一个新的指针,让指针指向String的地址空间。

char str[50] = "Hello, World";
char *pointer[50];
pointer[50] = &str[50];

4)最后我定义了一个新的字符串,并写入函数的结果,它通过指针调用,指针指向函数的指针。

char t[50] = (*functPtr)(pointer[50]);
printf("%s\n", str);
return(0);
}

不幸的是,我收到各种错误消息,例如:

Ü1.c:29:10: error: array initializer must be an initializer list or string literal
    char t[50] = (*functPtr)(pointer[50]);
         ^
    Ü1.c:27:5: warning: array index 50 is past the end of the array (which contains 50 elements) [-Warray-bounds]
        pointer[50] = &str[50];
        ^       ~~
    Ü1.c:26:5: note: array 'pointer' declared here
        char *pointer[50];
        ^
    Ü1.c:29:30: warning: array index 50 is past the end of the array (which contains 50 elements) [-Warray-bounds]
        char t[50] = (*functPtr)(pointer[50]);
                                 ^       ~~
    Ü1.c:26:5: note: array 'pointer' declared here
        char *pointer[50];
        ^
    2 warnings and 1 error generated.

【问题讨论】:

  • char (*functPtr)(char); 应该是 char *(*functPtr)(char *);,因为它需要一个 指针 指向一个字符,而不是一个字符。同样它返回一个指针。
  • char *pointer[50]; 将是一个包含 50 个指针的数组,您想说一个指向 50 个字符数组的指针。在 C 语言中我们不会那样说。我们只是说“指向 char 的指针”而不说有多少。所以char *pointer; 就足够了。
  • char t[50] = (*functPtr)(pointer[50]); 在 C 中不正确。您想将 funcPtr 的结果分配给数组 t。但是在这里,您将初始化与分配混合在一起。而且您不能将数组“分配”给 anor=ther 数组。你只能复制它。
  • @PaulOgilvie :非常感谢您对我的错误的解释,我真的很感激!我将最后一行更改为: printf("%s\n", (*functPtr)(pointer));这样我就不必复制数组了。现在我的代码编译了,但是不是“Hello World!”的反向字符串,而是在我的命令行中返回了“��”。我现在是返回指向值而不是值的指针吗?
  • 我看到你从你的问题中编辑了第一个错误。 不要不要那样做!这会使您的问题或cmets无法再被理解,因为它们所指的东西已经消失了。我重新编辑了错误。

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


【解决方案1】:

1) 定义一个指向函数的指针:

不,您没有定义指向函数的指针。您定义了一个名为 strrev 的函数。

2) 现在我在 main 中定义了一个指针,它与我的函数相匹配 上面定义:

int main(void) {

    char *(*functPtr)(char *);
    functPtr = &strrev;

是的,您定义了一个指向函数的指针,并使用函数strrev 的地址对其进行了初始化。由于表达式中使用的函数指示符被隐式转换为指向函数的指针,因此您可以编写

int main(void) {

    char *(*functPtr)(char *);
    functPtr = strrev;

3) 现在我定义了我想要反转的字符串,定义一个新的 指针,并让指针指向String的地址空间。

char str[50] = "Hello, World";
char *pointer[50];
pointer[50] = &str[50];

除了包含字符串的字符数组的定义之外,所有其他记录都没有任何意义。对于初学者,函数strrev 将字符串反转到位。它不会创建传递给它的字符串的反向副本。

如果你想声明一个指针,该指针将获得函数返回的反向字符串的地址,该地址等于原始字符串的地址,那么你可以写

char *pointer = functPtr( str );

4) 最后我定义了一个新的字符串并写入函数的结果, 它通过指针调用,它指向的指针指向 功能。

char t[50] = (*functPtr)(pointer[50]);
printf("%s\n", str);

您已经定义了一个指针,它将获取函数返回的值。所以再声明一个数组是没有意义的。此外,数组没有赋值运算符。该函数将原始字符串反转到位。你为什么要用原始反转字符串的副本再创建一个数组?!这完全没有意义。

您的程序可能如下所示

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

char * strrev( char *s )
{
    size_t n = strlen( s );

    if ( n )
    {
        for ( char *first = s, *last = s + n; first < --last; ++first )
        {
            char c = *first;
            *first = *last;
            *last = c;
        }
    }

    return s;
}

int main(void) 
{
    char * ( *fp )( char * ) = strrev;

    char s[] = "Hello, World";

    puts( s );
    puts( fp( s ) );

    return 0;
}

程序输出是

Hello, World
dlroW ,olleH

如果您最初希望该函数不会反转原始字符串,而是制作原始字符串的反向副本,那么在这种情况下,确实可以定义一个额外的字符数组来获取原始字符串的反向副本.

在这种情况下,程序可能看起来像。

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

char *reverse_copy( char *s1, const char *s2 )
{
    *( s1 += strlen( s2 ) ) = '\0';

    while (*s2)
    {
        *--s1 = *s2++;
    }

    return s1;
}

int main(void) 
{
    char * ( *fp )( char *, const char * ) = reverse_copy;

    char s[] = "Hello, World";
    char t[sizeof( s )];
    puts( s );
    puts( fp( t, s ) );

    return 0;
}

程序输出是

Hello, World
dlroW ,olleH

现在原始字符数组s没有改变,而数组t得到了存储在数组s中的原始字符串的反转副本。

【讨论】:

    【解决方案2】:

    我在这个答案中总结了我的 cmets,因为它为 cmets 的详细信息提供了更多空间。

    char (*functPtr)(char); 应该是char *(*functPtr)(char *);,因为它需要一个 pointer 指向一个字符,而不是一个字符。同样,它返回一个指针。

    char *pointer[50]; 将是一个包含 50 个指针的数组,您想说“指向 50 个字符数组的指针”。在 C 中,我们不会这么说。我们只是说“一个指向 char 的指针”,并没有说有多少。所以char *pointer; 就足够了。

    char t[50] = (*functPtr)(pointer[50]); 在 C 中不正确。

    您想将funcPtr 的结果分配给数组t。但是在这里,您将初始化与分配混合在一起。 char t[50]; 声明了一个包含 50 个字符的数组。您可以通过给它一个值来初始化它,例如 char t[50] = "Hello World"; 这将使编译器将“Hello World”复制到数组中。

    但是您尝试将函数指针分配给数组。您可能打算将函数的结果放入数组中。

    还请注意,您不能将一个数组“分配”给另一个数组。你只能复制它。

    所以正确的代码是:

    char *(*functPtr)(char *);
    functPtr = &strrev;
    
    char str[50] = "Hello, World";
    
    char t[50];
    char *s= funcPtr(str);  // call the function and save the returned pointer
    strcpy(t, s);           // now copy the result to your array.
    printf("%s\n", t);      // and print it
    

    注意:char str[50] = "Hello, World"; 是正确的,您会知道,char *str = "Hello, World"; 是错误的。为什么?因为第二个str 将指向只读内存(“字符串文字”),任何修改它的尝试都会中止程序。但在这里你做对了。

    【讨论】:

    • 非常感谢您的总结,代码现在可以工作了!您能否快速解释一下,为什么我可以只使用 char str[50] = "Hello World" 而不是创建一个指针,该指针指向该值,然后将该指针放入函数中?我想我必须传递一个指向函数的指针,让它请求一个(char *)。
    • 抱歉我的回复晚了。在 C 中,当您提及数组的名称时,它会“衰减”到其第一个成员的地址。换句话说,提及数组名称会导致使用指向数组的指针。因此,使用char *s= funcPtr(str);,您已经将一个指向str 的指针传递给它。
    猜你喜欢
    • 1970-01-01
    • 2012-05-05
    • 2020-02-20
    • 1970-01-01
    • 2012-06-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多