【问题标题】:How to check if there is a `\0` character in a filename using C?如何使用C检查文件名中是否有`\0`字符?
【发布时间】:2015-08-13 14:38:31
【问题描述】:

我想写一个这样的函数:

int validate_file_name(char *filename)
{
    //...
}

这将:

  • 如果文件名中没有 \0 字符,则返回 1,
  • 否则为 0。

我认为可以使用简单的for(size_t i = 0; i < strlen(filename); i++) 来实现,但我不知道如何确定我必须检查多少个字符?

我不能使用strlen(),因为它会在第一次出现\0 字符时终止。

我应该如何解决这个问题?


澄清:

我正在尝试将these guidelines 应用于我收到的文件名。如果您应该避免将\0 放在文件名中,那么如果您没有大小参数,您如何验证这一点。

此外,还有包含多个\0 字符的字符串,例如:http://www.gnu.org/software/libc/manual/html_mono/libc.html#Argz-and-Envz-Vectors。不过,我不知道如果没有明确提供它们的长度是不可能确定的。


结论:

您无法确定不是以 NULL 结尾的字符串的长度。除非你知道课程的长度或者你部署了一些肮脏的技巧:Checking if a pointer is allocated memory or not

【问题讨论】:

  • 需要尺寸参数。
  • 我正在实现一个头文件,我不能在那里改变任何东西。所以我无法提供大小参数。
  • 想一想:如果文件名可以包含空终止符,你怎么可能找到文件名的结尾?您将需要一个长度参数,或者一个指示字符串结尾的不同标记值。
  • 是的,我同意你们的观点,但这里的问题是: 1. 字符串 IS NULL 终止。 2. 它可能包含 NULL 字符,因为用户可以提供这样一个邪恶的文件名。 3.我认为通过检测为该字符串分配的内存块的大小可能有一些方法。
  • "每个 argz 向量由指向第一个元素的指针表示,类型为 char *,和大小,类型为 size_t.. 。”

标签: c string validation


【解决方案1】:

答案是,如果你不知道字符串的长度,你就不能写出这样的函数。

要确定字符串strlen() 的长度,搜索'\0' 字符,如果该字符不存在将导致未定义的行为。

如果你知道字符串的长度,那么,

for (int i = 0 ; i < length ; ++i)
 {
    if (string[i] != '\0')
        continue;
    return 1;
 }
return 0;

可以,如果你不知道字符串的长度,那么条件是

for (int i = 0 ; string[i] != '\0' ; ++i)

这显然意味着然后搜索 '\0' 没有任何意义,因为它的存在使所有其他与字符串相关的函数都能正常工作。

【讨论】:

    【解决方案2】:

    如果字符串不是以 NULL 结尾的,它还以什么结尾?如果你不知道,它的长度是多少?如果您知道这些问题的答案,那么您就知道您的问题的答案。

    【讨论】:

    • @MateuszPiotrowski 如果它可以包含\0,那么它不是一个以null 结尾的字符串,除非您认为第一个\0 是字符串的结尾。
    • 记住NULL是一个空的指针常量。请不要使用术语NULL 来指代空字符 '\0'。 (我知道你从问题中复制了用法。)
    • @GerardvanHelden:是的,它们几乎完全不同。
    • @MateuszPiotrowski:GNU C 文档没有讨论带有多个 '\0' 字符的字符串;它讨论了多个字符串,每个字符串都以'\0' 字符结尾。很简单,字符串不能包含嵌入的空字符。如果是这样,它就不是字符串了。
    • @KeithThompson 从概念上讲它们是,但实际上它们不是。但我真的不想参与辩论。这只是语义。如果你真的想开始,我支持你;):P
    【解决方案3】:

    您正在尝试解决一个不需要解决的问题。

    文件名是一个字符串。在 C 中,“字符串”根据定义是“一个连续的字符序列,以第一个 null 结尾并包括 字符”。

    不可能有一个包含空字符的字符串或文件名。

    字符序列可以嵌入空字符。例如:

    char buf[] = "foo\0bar.txt";
    

    buf 是一个 12 个字符的数组;位置 3 和 11 的字符都是空字符。如果您将buf 视为字符串,例如通过调用

    fopen(buf, "r")
    

    将被视为长度为3的字符串(字符串的长度不包括终止空字符)。

    如果您正在使用可能包含或不包含字符串的字符数组,那么按照您的要求去做是有意义的。您需要将缓冲区的大小与初始字符的地址分开跟踪,方法是传递一个附加参数或将指针和长度包装在一个结构中。

    但是,如果您正在处理文件名,几乎可以肯定最好只处理字符串并假设传递给您的函数的任何char* 值都指向一个有效的字符串。如果没有(如果数组中的任何地方都有 no 空字符),那是调用者的错,不是你可以合理检查的。

    (顺便说一句,Unix/Linux 文件系统明确禁止文件名中包含空字符。/ 字符也被禁止,因为它用作目录名称分隔符。Windows 文件系统有更严格的规则。)

    最后一点:NULL 是(扩展为)空 pointer 常量的宏。请不要使用术语NULL 来指代空字符'\0'

    【讨论】:

    • @iharob:不是不能解决的问题。这是调用者必须解决的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-14
    • 2015-07-15
    • 1970-01-01
    • 1970-01-01
    • 2020-05-06
    • 2016-08-17
    相关资源
    最近更新 更多