c语言指针在其它函数中崩溃,为什么C中的这个简单程序崩溃(数组VS指针)

"本文详细探讨了C语言中数组与指针的混淆实例,通过比较和实际代码演示,揭示了两者在声明和使用时的区别,以及著名的"C数组和指针等价性"原理。作者解释了为何看似相同的代码在不同情况下会导致错误,并展示了如何正确地将数组赋值给指针以及反之。"

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Steve Summit..

13

你的两个例子没有可比性.

在你的第二个例子中,你有

char a[] = "abcdefg";

char *p = a;

所以a是一个数组,并且p是一个指针.在图片中绘制它看起来像

+---+---+---+---+---+---+---+---+

a: | a | b | c | d | e | f | g | \0|

+---+---+---+---+---+---+---+---+

^

|

+----|----+

p: | * |

+---------+

这一切都很好; 该代码没有问题.

但在第一个示例中,在文件中1.c定义了一个名为的数组p:

+---+---+---+---+---+---+---+---+

p: | a | b | c | d | e | f | g | \0|

+---+---+---+---+---+---+---+---+

你可以根据需要命名一个数组" p"(编译器当然不关心),但是,在文件中0.c,你改变主意并声明它p是一个指针.您还声明(使用" extern"关键字)在p其他位置定义.所以编译器会接受你的话,并发出去往位置的代码,p并希望在那里找到一个指针 - 或者,在图片中,它希望找到一个包含箭头的框,指向其他地方.但它实际上发现了你的字符串"abcdefg",只是它没有意识到它.它可能最终会尝试将字节0x61 0x62 0x63 0x64(即构成字符串第一部分的字节"abcdefg")解释为指针.显然这不起作用.

你可以清楚地看到这一点,如果你改变了printf呼叫0.c到

printf("%p\n", p);

这会将指针的值打印p 为指针.(当然,p这不是一个真正的指针,但你对编译器说谎并且告诉它它是,所以当编译器将它视为指针时,你会看到的结果,这就是我们所说的试图在这里理解.)在我的系统上打印

0x67666564636261

这是字符串的所有8个字节,"abcdefg\0"顺序相反.(从这里我们可以推断出我在一台机器上,(a)使用64位指针而(b)是小端.)所以如果我试图打印

printf("%c\n", p[3]);

它会尝试从位置0x67666564636264(即0x67666564636261+ 3)获取一个字符并打印它.现在,我的机器有相当多的内存,但它没有那么多,所以位置0x67666564636264不存在,因此程序在尝试从那里获取时崩溃.

还有两件事.

如果数组与指针不同,你是怎么说的

char *p = a;

在你的第二个例子中,我说的那个"一切都很好;没有问题"?如何将右侧的数组分配给左侧的指针?答案是着名的(臭名昭着的?)"C中数组和指针之间的等价":实际发生的事情就像你说的那样

char *p = &a[0];

无论何时在表达式中使用数组,您获得的实际上是指向数组第一个元素的指针,就像我在本答案的第一张图片中所示.

当你问,"为什么它不起作用,虽然它在这里工作?",还有另外两种方法你可以问它.假设我们有两个功能

void print_char_pointer(char *p)

{

printf("%s\n", p);

}

void print_char_array(char a[])

{

printf("%s\n", a);

}

然后假设我们回到你的第二个例子

char a[] = "abcdefg";

char *p = a;

并假设我们打电话

print_char_pointer(a);

要么

print_char_array(p);

如果您尝试它,您会发现它们中的任何一个都没有问题.但这怎么可能呢?当我们调用时,如何将数组传递给期望指针的函数print_char_pointer(a)?当我们调用时,如何将指针传递给期望数组的函数print_char_array(p)?

好吧,记住,每当我们在表达式中提到数组时,我们得到的是指向数组第一个元素的指针.所以当我们打电话时

print_char_pointer(a);

我们得到的就像我们写的一样

print_char_pointer(&a[0]);

实际传递给函数的是一个指针,这是函数所期望的,所以我们没问题.

但是另一种情况呢,我们传递指向一个被声明为接受数组的函数的指针?嗯,实际上还有另一个原则是"C中数组和指针之间的等价".我们写的时候

void print_char_array(char a[])

编译对待它就好像我们写了一样

void print_char_array(char *a)

为什么编译器会做这样的事情?为什么,因为它知道没有数组将被传递给一个函数,所以它知道没有函数实际上会接收一个数组,因此它知道该函数将接收一个指针.这就是编译器对待它的方式.

(并且,非常清楚,当我们谈论"C中的数组和指针之间的等价"时,我们并不是说指针和数组是等价的,只是它们之间存在这种特殊的等价关系.我已经提到了两个已经完成了这三个等价的原则.以下是三个,供参考:(1)每当你在表达式中提到数组的名称时,你自动获得的是指向数组第一个元素的指针.(2)每当你声明一个似乎接受一个数组的函数,它实际上接受的是一个指针.(3)每当你使用"数组"下标操作符时[],在指针上,就像

p[i]你在实际得到的一样,就好像你有写的*(p + i).而且,事实上,如果你仔细想想,因为原则(1),甚至当你使用数组下标操作的东西,看起来像一个数组,你真正使用它的一个指针.但是,这是一个非常奇怪的想法,如果你不想,你不必担心,因为我 只是工作.)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值