检查char *指针是否为以null结尾的字符串的便携方法

时间:2015-01-27 07:40:39

标签: c string

我有一个C函数,它接受一个char *指针。函数的前提条件之一是指针参数是以空字符结尾的字符串

void foo(char *str) {
    int length = strlen(str);
    // ...
}

如果str不是指向以null结尾的字符串的指针,则strlen崩溃。是否有一种可移植的方法来确保char *指针确实指向以null结尾的字符串?

我在考虑使用VirtualQuery来查找str之后不可读的最低地址,以及我们是否在str的开头与该地址之间没有看到空终止符,然后str不指向以null结尾的字符串。

5 个答案:

答案 0 :(得分:10)

不,没有可移植的方式来做到这一点。以null结尾的字符串可以任意长(最多SIZE_MAX个字节) - 因此不是空终止的char数组也是如此。采用char*参数的函数无法知道它指向的有效内存块有多大(如果有的话)。检查必须遍历内存,直到找到空字符,这意味着如果数组中没有空字符,它将超过它的末尾,从而导致未定义的行为。

这就是为什么标准C库函数将字符串指针作为参数具有未定义的参数行为并不指向字符串。 (检查NULL指针很容易,但这只会导致一个错误情况,代价是有效参数执行速度较慢。)

编辑:回复您问题的标题:

  

检查char *指针是否为以null结尾的字符串的便携方法

指针不能是字符串。它可能是也可能不是指向字符串的指针。

答案 1 :(得分:2)

为了证明字符串的空终止,你不必证明存在空字符,你必须证明它存在恰好在正确的位置(不迟了,但也没有早些时候)。要做到这一点,你需要知道预期的内容或至少知道字符串的长度,此时验证非常简单......

考虑例如没有虚拟内存的设备:这意味着您可以遍历整个地址空间而不会触发任何类型的中断。

如果堆栈的地址高于堆,并且编译器将'\0'的副本放在堆栈上(而不是仅将其保存在寄存器中或将其用作立即值),则突然保证堆上的任何字符串都将被弱终止,因为您始终可以将验证码放在堆栈上的'\0'视为零终止符。

答案 2 :(得分:0)

正如其他人所指出的那样,没有可行的方法来做到这一点。原因是它没有用。

正常语义只检查NULL,并假设是否通过非NULL,它是有效的。毕竟,在您的指针之后可能会出现NULL 某处。唯一的另一种可能性是你遇到了未映射的内存。但是,即使使用虚假指针,您也会发现NULL。这意味着伪造的2000字符串仍然会通过支票。

答案 3 :(得分:0)

其他答案是正确的,但这是另一种思考方式。

如果指针指向 n char s的缓冲区,其中没有一个是'\0',那么只要您尝试检查 n + 1 字符,您处于未定义行为的范围内。因此,要扫描以查看是否存在'\0',它还不足以知道缓冲区末尾的某个上限,您必须知道完全缓冲区末尾的位置。

除了要求来电者提供给你之外,C还没有办法知道这一点。 VirtualQuery(假设它是可移植的)是不够的,因为在内存中的缓冲区之后可能会有其他对象。虽然它似乎适用于许多实现,但您依赖于未定义行为的事实意味着它必然是不可移植的。

答案 4 :(得分:0)

最好的办法是使用str n 函数将字符串的大小设置为上限。因此,如果您正在编写库调用并且不信任调用者,请记录您的调用,并注意字符串不能超过特定的合理大小,然后检查:

#define MAXNAME 32

if (strnlen(sketchyName,MAXNAME)==MAXNAME) return ERROR;