检查char *指针是否为以null结尾的字符串的便携方法
我有一个C函数,它接受一个char *指针。 函数的前提条件之一是指针参数是以空字符结尾的字符串
void foo(char *str) { int length = strlen(str); // ... }
如果str
不是指向以null结尾的字符串的指针,则strlen
崩溃。 是否有一种可移植的方法来确保char *指针确实指向以null结尾的字符串?
我正在考虑使用VirtualQuery
来查找不可读的str
后的最低地址,如果我们在str
的开头和该地址之间没有看到空终止符,则str
不指向以null结尾的字符串。
不,没有可移植的方法来做到这一点。 以null结尾的字符串可以任意长(最多为SIZE_MAX
字节) – 因此可以是非空终止的char
数组。 接受char*
参数的函数无法知道它指向的有效内存块有多大(如果有的话)。 检查必须遍历内存,直到找到空字符,这意味着如果数组中没有空字符,它将超过它的末尾,从而导致未定义的行为。
这就是为什么标准C库函数采用字符串指针作为参数具有未定义的参数行为并不指向字符串。 (检查一个NULL
指针很容易,但这样只能捕获一个错误情况,代价是有效参数执行速度较慢。)
编辑:回答你的问题标题:
检查char *指针是否为以null结尾的字符串的便携方法
指针不能是字符串。 它可能是也可能不是指向字符串的指针。
要certificate字符串的空终止,您不必仅certificate存在空字符,您必须certificate它存在于正确的位置 (不晚,但也不早)。 要做到这一点,你需要知道预期的内容或至少字符串的长度,此时validation非常简单…
考虑例如没有虚拟内存的设备:这意味着您可以迭代整个地址空间而不会触发任何类型的中断。
如果堆栈的地址高于堆,并且编译器在堆栈上放置'\0'
的副本(而不是仅将其保存在寄存器中或将其用作立即值),则突然可以保证任何字符串在堆上将被弱终止,因为您总是能够将您的validation代码放在堆栈上的'\0'
视为零终止符。
正如其他人所指出的那样,没有可行的方法来做到这一点。 原因是它没用。
普通语义只检查NULL
,并假设如果传递非NULL,则它是有效的。 毕竟,你的指针之后某处可能会出现NULL
。 唯一的另一种可能性是你遇到了未映射的内存。 然而,更有可能的是,即使使用虚假指针,您也会发现NULL
。 这意味着伪造的2000字符串仍然会通过检查。
其他答案是正确的,但这是另一种思考方式。
如果指针指向n个 char
的缓冲区,其中没有一个是'\0'
,那么只要你尝试检查n + 1字符,就会出现未定义的行为。 因此,要扫描以查看是否存在'\0'
,要知道缓冲区末尾的某个上限是不够的,您必须确切知道缓冲区末尾的位置。
C不会让你知道这一点,除了要求调用者提供给你。 VirtualQuery(假设它是可移植的)是不够的,因为在内存中的缓冲区之后可能会有其他对象。 虽然它似乎可以在许多实现上工作,但是您依赖于未定义的行为这一事实意味着它必然是不可移植的。