我正在学习C,试图实现一个通用的交换函数,它能够交换字符串和数组。我认为这是可能的,因为字符串和数组本质上是内存中的数组,我没有交换实际的字节,而只是指针。下面是我的实现:
#include "stdio.h"
void swap(void **a, void **b) {
void *tmp;
tmp = *b;
*b = *a;
*a = tmp;
}
void print_array(char *c, int size) {
for (int i = 0; i < size; ++i) {
printf("%c ", c[i]);
}
printf("\n");
}
int main() {
char *h = "hell";
char *w = "world";
printf("%s %s\n", h, w);
swap((void **)&h, (void **)&w);
printf("%s %s\n", h, w);
char c[5] = { 'a', 'e', 'i', 'o', 'u' };
char d[3] = { '1', '2', '3' };
print_array(c, 5);
print_array(d, 3);
swap((void **)&c, (void **)&d);
return 0;
}
结果是:
hell world
world hell
a e i o u
1 2 3
*** stack smashing detected ***: terminated
Aborted (core dumped)
正如您所看到的,这个通用的swap函数可以交换两个字符串,但是当输入是数组时,它会触发core dump。我不明白我对指针和数组的理解哪一部分是错误的。
3条答案
按热度按时间des4xlb01#
数组不是指针。
&c
不是char **
。是的,你可以对一个数组做
*c
和*(c + 2)
以及其他类似指针的事情,这自然会让你认为它是一个指针,但它不是。这些之所以有效,是因为数组在许多情况下都被 * 隐式转换 *(“衰减”)为指针(指向其第一个元素),包括那些情况。结果指针是临时的(右值),它在需要时进行动态计算,否则不会存储在内存中。数组中唯一存储的东西是它的元素。
一个数组不衰减为指针的情况之一是
&c
。这不会返回char **
(指向char
的指针),这不可能工作,因为衰减产生的指针是计算的,而不是持久存储在内存中。相反,您会得到一个
char (*)[5]
类型的指针(指向5
char
s数组的指针),它与&c[0]
具有相同的值,但类型不同(&c[0]
是char *
)。因为没有指向交换的底层指针,所以你想要的是不可能的。
你能做的最接近的事情就是遍历每个数组元素并交换它。这要求数组具有相同的长度。大概是这样的:
myss37ts2#
您可以设计一个通用的交换函数来交换任何类型的对象,但是要使交换成为可能,对象必须具有相同的大小。这里的字符串指针确实有相同的大小,
sizeof(char *)
,这与sizeof(void *)
相同,所以你的代码应该像预期的那样工作,尽管它违反了严格的别名规则。相反,sizeof(c) != sizeof(d)
,所以交换这些数组是不可能的,而且,你的交换函数不够通用,不能交换大小不完全是指针大小的对象。最根本的误解似乎是数组是不是指针。
h
和w
是指向char
的数组的指针,初始化为指向字符串文字,这些文字是char
的(不可修改的)数组,而c
和d
是resp的实际数组。6和4字节。将c
传递给一个函数,比如print_array
,确实传递了一个指向它们的第一个元素的指针,但这并不能使它们成为指针。下面是一个修改后的版本,带有一个通用的swap函数,并定义了行为:
i1icjdpr3#
不能使用同一个函数来交换指针和数组。
例如,要交换两个数组,您需要交换它们的元素。
也就是说,你不能交换地址的范围内存occupeid数组。只能交换数组占用的内存区的内容。
下面是一个简单的演示程序,它显示要交换两个数组的内容,您需要交换它们的元素对
程序输出为
至于你的功能
那么从这个声明中可以清楚地看到,
它只交换两个
void *
类型的指针。例如不能交换两个字符,因为sizeof( char )
小于sizeof( void * )
。对于错误,例如表达式
&c
的值是数组c
的第一个元素的地址值。在函数
swap
中解引用地址的操作读取由作为其元素
{'a', 'e', 'i', 'o', 'u'};
的数组占用的存储器作为导致未定义行为的地址的值。