fsantinize 还没智能到那种程度 简直给码农添加负担
给一个静态字符数组前面添加几个空格都会报错
请看
图 1

图 2

图 3

编译时报图 3 的错误 运行就报
==1856626==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fff15ef59e9 at pc 0x55d429175340 bp 0x7fff15ef5940 sp 0x7fff15ef5938

是把字符串连双引号拷贝进浏览器 console 用.length 算出来的 是 30 再加 1 等于 31刚才把下标 31 去掉了 用 sizeof 打印出来是 31但编译加上 fsanitize 还是报错这贴讨论的是 fsanitize 的弱智 但它还想做全面的事情 限制了码农的能力 增加了繁琐你们着眼的细节是我在增加了很多空格后 无非是忘了改下标你们自己去加上 fsanitize 编译看看

你是真不懂还是在钓鱼?

不懂 没做过 c c++项目 只会写小代码

编译报错是合理的运行时报错不合理啊

你数数这数组多长了

这么几个字节对现代计算机来说算啥 有必要 sanitize 不能运行?

笑拉了

我的意思是,你看看你的初始化字符串的长度和为这个 char[]分配的长度,你的代码里为它分配了 25 个 char ,去掉末尾的\0 ,你的字符串长度应该是 24 个 ascii 字符

估计是来炸鱼的

你实在搞不明白,你就直接 char s[INT_MAX]吧

哈哈哈,给我逗笑了

认真的?😅

  1. 为什么编译时 warning 是合理的,而运行时报错就不合理呢?2. 从内存的层面上看,OP 期望运行时它是怎么样的呢?

搁这钓鱼呢?笑死我了,报错那么明显

char 的长度下标的确写错了 但下面这样也不行 总共 30 个字符 + 一个末尾'\0'![]( )

。。。。。。

我既然能写出这种 while 循环 数组下标还是知道的 只是被 fsantinize 冲昏了

而且 leetcode 的函数设计有问题 一个函数传只一个指针 还开 fsantinize

看完标题:OP 搁着炸鱼?看完下面回复:难道这 OP 真的不懂?看了一下 OP 的其他帖子:哦,原来是真小白啊

我此时很想看到那个秒杀 nginx 的哥们来点拨一下 OP

难绷,建议去问 gpt ,这种事浪费大家时间不值得

建议还是放弃使用 c/cpp 吧

能留个微信吗,用 sha256 加密一下发出来

哈哈,这个梗我居然看懂了

你以为我连这都不知道吗 无法还原

人眼数很容易数错的,对于比较长的字符串,最好还是写成char s[] = "这是字符串"中括号内不写任何数字如果想知道 s 数组有多长,那就 sizeof(s)以 14 楼的图为例,把 s[31]的数字去掉,改成 s[],接着下面一行加一句printf("sizeof s: %d\n", (int)sizeof(s));就可以准确知道实际大小

是把字符串连双引号拷贝进浏览器 console 用.length 算出来的 是 30 再加 1 等于 31刚才把下标 31 去掉了 用 sizeof 打印出来是 31 但编译加上 fsanitize 还是报错这贴讨论的是 fsanitize 的弱智 但它还想做全面的事情 限制了码农的能力 增加了繁琐 你们着眼的细节是我在增加了很多空格后 无非是忘了改下标你们自己去加上 fsanitize 编译看看

#26 "无非”是忘了改下标...fsantinize 帮你找出了这么严重的问题,这时候你就应该默默在心中唱一首《感恩的心》。

关键是没有下标 或刚好等于 或远远大于数组元素个数 fsanitize 都报错 这不是假阳性么?所以说它弱智 但还想干全能的事

请问楼主期待这段代码发生什么?int a[1];a[0] = 1;a[1] = 2;用超长字符串初始化不够长的字符数组的效果和上面差不多。另外楼主并不是忘了改下标,而是忘了改长度,这是两个不同的概念。另外 char s[] = "..."; char s2[strlen(s) + 1]; 不是合法的 C++ 代码,没有拒绝编译已经很给面子了。

是 gcc 编译器你那段代码 不就是越界么 段错误 这贴的主题是 fsanitize 检查出假阳性 因为正确的数组长度比如 31 它也报错 我当然知道越界

这个是合法的 char s2[strlen(s)+1]不合法的话 你用数组长度+1 的 size 用 malloc 返回指针都不合法

我不知道越界的话 这种高质量 while 循环都写不出来

一开始数组下标是正确的 我当时好像去掉了下标 后来又加上正确下标 我发现 fsanitize 报假阳性 为了截图 才改了代码 改了字符串 你们没有关注假阳性 反而关注细枝末节

#30 所以你对 char s[25] = "长度为 30 的字符串长度为 30 的字符串"; 出错有什么异议呢?另外 s 以空格开头的时候,在while (start > s) {flag = 0;while (*start == ' ') start--;这段代码里面会把 start 减到 s 之前,这也是未定义行为。 gist.github.com/GeeLaw/47dea7677eb48e1b9896bfe9d006b5f4

你的 while 里面的while(*start==' ') start--;在字符串以空格开头的时候可能会越界,访问到 s[-1]

简单写了一小段#include <stdio.h>int main(){ char str[30] = " www.hesudu.com/t/974343"; printf("sizeof str: %d\n", (int)sizeof(str)); printf("%s\n", str);}无论 GCC 还是 Clang ,编译和运行都没报错编译的命令行:cc -fsanitize=addressGCC 版本(运行在 Debian 11 ):10.2.1Clang 版本(运行在 FreeBSD 13.2 ):14.0.5

#31 C++ 不存在变长数组,所以 int n; scanf("%d", &n); int a[n]; 是完全错误的,即使 n 输入的是 1 也是错误的。

减到 s 之前也没问题 下面 start2++ 刚好指向空格 下面的代码不会执行

后面先+1 了 刚好指向空格

这里没有 c 板块 只有 c++我本来想发 c 板块

减到 s 之前是有问题的。因为你这个循环至少还会再判断一次条件,必然会非法读取越界位置 s[-1]的值,这是不允许的。所以说 sanitizer 会报错。而且你也不知道 s 前面有什么二进制数据,“下面 start2++ 刚好指向空格”,指针没有跑飞只是运气好。

char s[] = "add";这样也是合法的 编译期就能确定长度 再简单不过的事

补充一条,无论是以 C 语言还是 C++来编译,同样都没报错

假如 s 数组前面二进制数据一堆 0x20 ,指针就跑飞了

#28 聪明的你倒是把数组长度正确的,会报假阳性的代码贴上来啊...建议聪明的你别用截图,难道指望其他人对着你的图手打一遍代码么...

减到非空格的位置退出 while 循环+1 不是刚好指向空格吗?还需要什么运气?我发现 fsanitize 对字符串增加到一定长度后才报错

数组名前面就是一个 byte 不过不属于数组 吓谁啊 别小看了这几个 while 循环 是老鸟才能写得出来的

#38int a[1];a + 0; // OKa + 1; // OKa - 1; // 未定义行为a + 2; // 未定义行为和 (a-1)、(a+2) 有没有被解引用没有任何关系。见 C++ 标准 [expr.add]/4:When an expression J that has integral type is added to or subtracted from an expression P of pointer type, the result has the type of P.(4.1) If P evaluates to a null pointer value and J evaluates to 0, the result is a null pointer value.(4.2) Otherwise, if P points to an array element i of an array object x with n elements ([dcl.array]), the expressions P + J and J + P (where J has the value j) point to the (possibly-hypothetical) array element i+j of x if 0≤i+j≤n and the expression P - J points to the (possibly-hypothetical) array element i−j of x if 0≤i−j≤n.(4.3) Otherwise, the behavior is undefined.注意 4.2 要求表达式的结果指向数组对象或者数组末尾之后,不允许数组开头之前。

#include "stdio.h"#include "stdlib.h"#include "string.h"int main(int argc, char *argv) { char s[] = " a bc ed sdff";printf("%d\n%d\n",sizeof(s),strlen(s)); char start, start2; start = s; while ( start != '\0') { start++; } --start; char s2[strlen(s) + 1]; char s2p = s2; char flag; while (start > s) { flag = 0; while ( start == ' ') start--; while (start >= s && start != ' ') start--; start2 = start; ++start2; while ( start2 != ' ' && start2 != '\0') { s2p++ = start2++; if (flag == 0) flag = 1; } if (flag == 1) { s2p++ = ' '; } } s2p = '\0'; start = s; s2p = s2; while ( s2p != '\0') start++ = s2p++; *start = '\0'; printf("%s\n%d\n", s, (int) strlen(s));}编译:cc c.c -fsanitize=address -fsanitize-recover=address -fno-omit-frame-pointer -O0 -Wall

#47 假设编译器不检查内存,并且数组前面全是空格呢?另外这个 while 循环写得可以说是乱七八糟了。

#49
字符串结尾不是空格的话,while(*start2 != ' ')没有判\0 会超出 s2 范围,一路写出范围

#47 接续 #50 ,假设数组前面一切可读取的虚拟内存都是 ' ',且假设指针加减运算未定义行为的实现就是访问这些虚拟内存,那么这个程序会因为把 start 减到不可读的虚拟内存地址之后继续读 start 而访问违规,从而崩溃。

这里需要把 while(start2 != ' ') 改成 while(start2 != ' ' && start2 != '\0') 嗯 这里需要把 while(start = '' ) 改成 while(start >=s && *start == '')

第 14 层 早就加了字符串末尾判断

那你有什么更好的 while ? 已经是最高效的了

重新申明:fsanitize 无论字符串多短 都报错了 早上具体什么情况 一会报错 一会不报错 想不起来了

#40没有 c 板块? hesudu.com/go/c

别尬黑,人好歹是会写 epoll 的,只是不会配 nginx 而已

“别小看了这几个 while 循环 是老鸟才能写得出来的”今日 V2EX 笑话

hesudu.com/t/974127#reply10 楼主不会写反转字符串,开了两个帖子一个骂 c 语言一个骂工具链

hesudu.com/t/853017#reply244 破案了,写 php 的zzzkkk symfony form choicetype 怎么设置选中项PHP • zzzkkk • 2021-12-31 18:36:59 PM 忽略 zzzkkk symfony 每次改动 config/services.yml 都加载很慢PHP • zzzkkk • 2021-12-30 14:47:08 PM • 最后回复来自 zzzkkk 忽略 7zzzkkk symfony form money type 为什么存到数据库 是价格乘以 100 ?PHP • zzzkkk • 2021-12-30 15:12:32 PM • 最后回复来自 zzzkkk 忽略 6zzzkkk symfomy form add field 注解模式 property_path 无效PHP • zzzkkk • 2021-12-25 20:30:33 PM 忽略 zzzkkk symfony 项目每次改动都要 clear cache?这是把 V2EX 当 chatgpt 使呢?

我这代码还真把字符串反转了 你有本事写个更高效的出来

是字符串里的单词顺序反转 不是简单字母反转

你有本事写个更高效的 c 代码出来

没用过的臃肿框架 不知道不是很正常么

#63 #64 #1start = s;while ( *start != '\0') {start++;}--start;#2char s2[strlen(s) + 1];看完前面这几行已经可以优化了,后面不看了 XD

各位 c c++老鸟 谢谢了 我的确没做过 c c++项目 但是我这个算法还是最好的吧

OP 把系统版本、编译器版本一起发出来吧我用 GCC 10.2.1 (Debian 11)、GCC 13.2.1 (Fedora 38)和 Clang 14.0.5 (FreeBSD 13.2)都没遇到 OP 主贴图 3 的情况

gcc (Debian 10.2.1-6) 10.2.1 20210110aws 的 tiny instance

你可以把会导致 sanitizer 报错的代码原样贴出来,大家来一起帮你数一数到底有多少个字符 godbolt.org/

误以为进了民科吧

哎呀 不知怎么回事 刚才好像是一条 printf 语句到了 sanitize 问题现在改成这样 在 linux 上能运行了 但在 leetcode 上还不能运行 godbolt.org/z/M7Wq9hddP

属实是看不下去了 sanitizers 系列工具 已经是误报率非常低的动态扫描方式了,楼主几乎在重复在类似的问题上犯错不好好看文档 就上所有动态扫描的编译选项不会用在正常的软件上开启 仅仅在需要的时候开启 另外如果想让扫描结果 尽可能准确 需要添加回溯和调试的编译选项-fno-omit-frame-pointer -g多看看官方文档吧 github.com/google/sanitizers/wiki/AddressSanitizer

楼主可能的理论基础不够强,以为编译过就是合法的代码,其实这是编译器帮你做的优化,举个你刚才的例子在栈中开辟数组要指定大小,而且还的是字面量或者 const 量,但是在高版本 gcc 或者高版本 msvc 中编译器会在编译阶段计算出并给你填上。建议使用低版本的编译器来学习 C++

楼主你可以用 rust 去刷 leetcode ,性能不输 C++,而且不会随便就 runtime 报错

OP 贴出来的报错明显是编译期警告(连报错都不是),一看就知道不是 runtime 报错

是运行时报错 没贴上来 是一个 stack buffer overflow 类似的 santinize 产生的

你把这里的 reversWords 贴到 leetcode cn 好像第 141 题它还报错 但是在 linux 编译 已经可以运行了 godbolt.org/z/M7Wq9hddP

这不算最好的算法,太繁琐了。最方便的写法是:全句字母反转 + 每个单词内部字母反转 = 单词顺序反转全句字母反转,只要遍历一遍就可以然后再对每个单词内部字母反转,只要正序抠单词,顺便去空格比你倒着抠单词方便太多

这“老鸟”看得我一愣一愣的LeetCode 考察算法和数据结构,和编程语言关系不大,“c c++老鸟”也未必不翻车(暂且不讨论这 while 究竟是不是“高质量”)而且 LC 上的题目在算法领域也是入门级的那一类,做了几道 LC 上的题目(甚至都没 AC )就能叫“老鸟”真让人摸不着头脑。任何一个正规的大学计算机系开设的数据结构与算法必修课教学的内容深度都比它高得多(当然指的是熟练掌握了课内知识,仅仅及格混过考试不算)。做过 LC 就称“老鸟”真不够格(除非 Hard 题能随便秒,这种情况另说)。如果想见识真正的“老鸟”,建议看看洛谷、POJ 、Codeforces 这些网站。

你说的这个算法没有我这个算法清晰明了 符合直觉 而且遍历一遍也完不成

“高质量 while”,那确实是大佬了

不熟悉 C 的话不建议直接用它刷题了,容易自找困扰,当输入是"A B"时,你上面代码第30行,34行都会写越界

写这么多 while 属于看着就血压高了,寻找单词就看寻找边界就行,一个 while/for 反向找单词边界然后输出就够了