练习9:数组和字符串笨办法学C 附加题

  • 有时Valgrind并不能发现你犯的错误,则需要移动声明这些变量的地方看看是否能找出错误。这是C的黑魔法的一部分,有时变量的位置会改变bug。

在C语言中,直接改变内存地址的值需要使用指针。指针是一个变量,它存储了内存地址。通过修改指针所指向的内存地址上的值,可以直接改变内存地址的值。

要改变内存地址的值,可以按照以下步骤进行操作:

声明一个指针变量,并为其分配内存地址。例如:


int *ptr;
int number = 42;
ptr = &number;  // 将指针ptr指向变量number的内存地址

使用解引用操作符*访问指针指向的内存地址上的值,并对其进行修改。例如:

*ptr = 100;  // 修改ptr指向的内存地址上的值为100

通过上述操作,就可以直接改变指针所指向的内存地址上的值。

int *ptr;
ptr=&name[3];
*ptr='A';

请添加图片描述
直接系统内存崩了
Valgrind报告中的错误 “*** stack smashing detected ***” 是一种堆栈溢出的错误。它通常表示在程序中发生了缓冲区溢出,导致堆栈被破坏,从而触发了堆栈保护机制。

堆栈溢出可能是由于以下原因之一引起的:

缓冲区写入超出其分配的空间。这可能是由于字符串操作函数(如strcpy、sprintf等)在目标缓冲区没有足够空间时写入了过多的数据。

**缓冲区没有正确地以空字符(\0)结尾。**字符串在C中是以空字符作为结尾的,如果缓冲区没有正确地以空字符终止,那么后续的字符串处理函数可能会导致越界访问

要解决此问题,您可以检查程序中涉及缓冲区操作的部分,并确保缓冲区的大小足够容纳所写入的数据,并在必要时添加适当的空字符终止符。

在上述Valgrind报告中,没有显示明确的内存泄漏错误,但它显示了1,024字节的堆内存仍然可达。这可能是因为程序分配了堆内存但没有释放它,导致可达的内存块。
您可以使用–leak-check=full选项重新运行Valgrind,以获取有关泄漏内存的详细信息。

已经自动–leak-check=full

==4542== Process terminating with default action of signal 6 (SIGABRT)
==4542==    at 0x4903A7C: __pthread_kill_implementation (pthread_kill.c:44)
==4542==    by 0x4903A7C: __pthread_kill_internal (pthread_kill.c:78)
==4542==    by 0x4903A7C: pthread_kill@@GLIBC_2.34 (pthread_kill.c:89)
==4542==    by 0x48AF475: raise (raise.c:26)
==4542==    by 0x48957F2: abort (abort.c:79)
==4542==    by 0x48F66F5: __libc_message (libc_fatal.c:155)
==4542==    by 0x49A3769: __fortify_fail (fortify_fail.c:26)
==4542==    by 0x49A3735: __stack_chk_fail (stack_chk_fail.c:24)
==4542==    by 0x109359: main (ex9.c:49)
==4542== 
==4542== HEAP SUMMARY:
==4542==     in use at exit: 1,024 bytes in 1 blocks
==4542==   total heap usage: 1 allocs, 0 frees, 1,024 bytes allocated
==4542== 
==4542== LEAK SUMMARY:
==4542==    definitely lost: 0 bytes in 0 blocks
==4542==    indirectly lost: 0 bytes in 0 blocks
==4542==      possibly lost: 0 bytes in 0 blocks
==4542==    still reachable: 1,024 bytes in 1 blocks
==4542==         suppressed: 0 bytes in 0 blocks
==4542== Rerun with --leak-check=full to see details of leaked memory
==4542== 
==4542== For lists of detected and suppressed errors, rerun with: -s
==4542== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

(1) “definitely lost” 意味着你的程序一定存在内存泄露;
(2)”indirectly lost”意味着你的程序一定存在内存泄露,并且泄露情况和指针结构相关
(3) “possibly lost” 意味着你的程序一定存在内存泄露,除非你是故意进行着不符合常规的操作,例如将指针指向某个已分配内存块的中间位置。
(4) “still reachable” 意味着你的程序可能是没问题的,但确实没有释放掉一些本可以释放的内存。这种情况是很常见的,并且通常基于合理的理由。
(5)”suppressed” 意味着有些泄露信息被压制了。在默认的 suppression 文件中可以看到一些 suppression 相关设置。

  • 将一些字符赋给numbers的元素,之后用printf一次打印一个字符,你会得到什么编译器警告?

打印的数据不对
这个警告 “warning: multi-character character constant [-Wmultichar]” 出现是因为在代码中使用了多字符字符常量。C语言中,字符常量通常只能包含一个字符,例如 ‘a’, ‘b’, ‘1’ 等。但是如果你使用了类似 ‘ab’, ‘12’ 或者其他多个字符组成的字符常量,编译器会给出这个警告。
多字符字符常量的行为是依赖于编译器的,不同的编译器可能会有不同的实现。在某些情况下,多字符字符常量会被解释为一个整数值,其结果是不确定的。
如果你希望在程序中表示多个字符的组合,你可以使用字符串常量(使用双引号括起来的字符序列),例如 “ab”, “12”。这样可以避免多字符字符常量带来的问题。

在这里插入图片描述
修改
int numbers[4] = {‘abc’,‘def’};
18 printf(“numbers: %c %d %d %d\n”,
19 numbers[0], numbers[1],
20 numbers[2], numbers[3]);
在这里插入图片描述
得到def结果为6579558
对应def的ASCII的值
在这里插入图片描述

  • 对names执行上述的相反操作,把names当成int数组,并一次打印一个int,Valgrind会提示什么?
    在这里插入图片描述
ex9.c:5:25: warning: overflow in conversion from ‘int’ to ‘char’ changes value from ‘456’ to ‘-56[-Woverflow]

123的ASCII是{
456的 那个东西

  • 如果一个字符数组占四个字节,一个整数也占4个字节,你可以像整数一样使用整个name吗?你如何用黑魔法实现它?
  • 在这里插入图片描述
    在这个示例中,我们将int_ptr指针的地址使用%p格式说明符打印出来。需要注意的是,为了正确使用%p,我们需要将int_ptr强制转换为void类型,因为%p期望的是void类型的指针。
    在这里插入图片描述
    考虑一个32位整数 int x = 0x12345678; 的存储方式
低地址                高地址
+------+------+------+------+
| 0x78 | 0x56 | 0x34 | 0x12 |
+------+------+------+------+

在小端模式下,最低有效字节存储在低地址,而在大端模式下,最高有效字节存储在低地址。大多数现代计算机都采用小端模式。

  • 将name转换成another的形式,看看代码是否能正常工作。

在这里插入图片描述
无错误正常。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weixin_44781508

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值