使用指向函数的指针反转字符串,该函数执行字符串反转

Reverse String with a pointer to a function, which executes the String reverse

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

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的地址space。

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

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

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.

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

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

char *pointer[50]; 将是一个包含 50 个指针的数组,您想说 "a pointer to an array of 50 chars"。在 C 语言中我们不这么说。我们只说 "a pointer to a char" 而没有说多少。所以 char *pointer; 就足够了。

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

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

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

另请注意,您不能 "assign" 一个数组到另一个数组。只能复制。

所以正确的代码是:

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 将指向只读内存("string literal")并且任何修改它的尝试都会中止程序。但在这里你做对了。

1) Define a pointer to a function:

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

的函数

2) Now in my main I define a pointer, which matches the function I defined above:

int main(void) {

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

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

int main(void) {

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

3) Now I define the String, which I want to reverse, define a new pointer and let the pointer point to the address space of the String.

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

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

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

char *pointer = functPtr( str );

4) Lastly I define a new String and write the result of the function, which call through the pointer, which points to the pointer to the function.

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 ) ) = '[=17=]';

    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.

中的原始字符串的反向副本