【问题标题】:Why does this swapping of strings through pointers work in C?为什么这种通过指针交换字符串在 C 中起作用?
【发布时间】:2021-12-01 14:29:50
【问题描述】:

据我所知,当我们创建一个数组或字符串时,它们的名称是指向它们的第一个元素的指针。在这种情况下,指针无法更改。

但是,这段代码可以工作:

#include <stdio.h>

void swapString(char **str1_ptr, char **str2_ptr)
{
    char *temp = *str1_ptr;
    *str1_ptr = *str2_ptr;
    *str2_ptr = temp;
}

int main()
{
    char strings[][30] = {"Test1","Test2","Test3"};
    int i;
    
    swapString((char **)&strings[0],(char **)&strings[1]);
    
    for(i=0;i<3;i++){
        printf("%s\n",strings[i]);
    }
    
    return 0;
}

为什么这很好用? 以这种方式交换字符串(或一般的数组)是一种好习惯吗? 什么时候使用这种方法不是一个好主意?

【问题讨论】:

  • 为什么指针不能改变?是什么阻止了它?
  • @Cheatah 实际上,据我所知,名称 os 字符串和数组所指向的地址无法更改。我们可以改变它吗?
  • 是的,如果它们没有被声明为const。最大的风险是您的函数假设它只能更改指针,而实际上指针被放在一些只读部分中。这取决于开发人员跟踪并正确应用 const 说明符。
  • @Cheatah 不涉及指针,而是一个数组。

标签: arrays c string pointers


【解决方案1】:

为什么这很好用?

效果不好。 它似乎运作良好,因为您对编译器撒谎并使用了不足的测试数据。

void swapString(char **str1_ptr, char **str2_ptr)
{
    char *temp = *str1_ptr;
    *str1_ptr = *str2_ptr;
    *str2_ptr = temp;
}

您声称提供了指向指针的指针。因此,此函数在两个位置之间交换的字节数与指针占用的字节数一样多。在大多数系统上是 4 或 8 个字节。

但是你传递的是数组的地址,而不是指向指针的指针:

    char strings[][30] = {"Test1","Test2","Test3"};
    
    swapString((char **)&strings[0],(char **)&strings[1]);

这会导致未定义的行为。您正在使用强制转换,因为您的编译器告诉您,如果您删除它们,这是螃蟹:

test.c:15:28: warning: passing argument 2 of ‘swapString’ from incompatible pointer type [-Wincompatible-pointer-types]
   15 |     swapString(&strings[0],&strings[1]);
      |                            ^~~~~~~~~~~
      |                            |
      |                            char (*)[30]
test.c:3:41: note: expected ‘char **’ but argument is of type ‘char (*)[30]’

因此,该函数认为它交换了一个指针,但实际上它交换了数组的前 8 个字节。

要验证这一点,您可以使用更长的字符串:

#include <stdio.h>

void swapString(char **str1_ptr, char **str2_ptr)
{
    char *temp = *str1_ptr;
    *str1_ptr = *str2_ptr;
    *str2_ptr = temp;
}

int main()
{
    char strings[][30] = {"Test111111","Test222222","Test333333"};
    int i;

    swapString((char **)&strings[0],(char **)&strings[1]);

    for(i=0;i<3;i++){
        printf("%s\n",strings[i]);
    }

    return 0;
}

然后你就会得到你应得的结果。 ;)

Test$ ./test
Test222211
Test111122
Test333333

如果是 32 位地址,您需要区分字符串的前 4 个字节。

如您所见,根本没有交换指针。只是数组的开头搞砸了。

如果你想通过交换指针来交换字符串,你需要改变你的数组定义:

    char *strings[] = {"Test111111","Test222222","Test333333"};
    swapString(&strings[0],&strings[1]);

作为副作用,您还可以从函数调用中删除强制转换,因为类型现在符合预期。

【讨论】:

  • 很好的解释!谢谢!
猜你喜欢
  • 2021-04-30
  • 2015-11-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多