如果 c 字符串以 null 终止,这将如何工作?
How does this work if c strings are null terminated?
我写了一个小程序来测试 c 中的字符串,但我无法理解为什么它在看似不应该的时候起作用,代码是:
#include <stdio.h>
int main() {
char name[5];
printf("Enter your name: ");
scanf("%s",name);
printf("you entered: %s\n",name);
printf("your name is %d letters long\n", strlen(name));
return 0;
}
输入一个 5 个字母的名字,我希望 运行 遇到麻烦,因为我无法将 5 个字符 + 空字符 ender 放入大小为 5 的数组中,但是程序运行正常:
其他答案没有错,但没有完全回答问题。
之所以可行,是因为 c 对内存限制不严格。即使您已经分配了一个长度为 5 的 char 数组,您也可以将其填充到数组末尾之后,c 不会阻止您。
当您将 name
传递给 printf()
时,它只是从数组的开头开始读取内存,直到到达空终止符 [=12=]
。 strlen()
也是一样,只是counts until it reaches the null terminator.
本帖中的其他回答也提到了这一点,但没有提供资源来帮助您更好地理解这个问题。所以,这就是我要做的。
您已经创建了第一个缓冲区溢出错误。这是因为C没有memory safety,也就是说除非用户明确实现,否则对内存的边界没有限制。
在您的例子中,函数 scanf("%s",name);
从用户那里获取数据并将其放入缓冲区。此函数不检查内存边界。这意味着如果输入大小大于分配的缓冲区,则您正在分配的内存之外写入。在许多情况下,它是无害的。然而,它可能是真正难以找到的错误和一些漏洞的来源。关于 buffer overflow 的维基百科文章非常好,并且对所有内容进行了非常详细的解释,这应该可以帮助您更好地理解。
你用来读取字符串长度的函数strlen(name)
,也不做边界检查。如果您查看 strlen 的手册页,您会发现它没有提及任何有关内存边界的内容。相反,它声明它计算字符串开头和下一个终止空字节之间的长度。
The strlen() function calculates the length of the string pointed
to by s, excluding the terminating null byte ('[=12=]').
那么,为什么您的应用程序可以运行?
你有一个写时不关心内存边界的函数,你有一个读时不关心内存边界的函数。
如何防止它发生?
幸运的是,您不是第一个遇到此问题的人。如果您有兴趣了解如何防止这种情况发生,我建议您查看此 post How to prevent scanf causing a buffer overflow in C? 。如果你是初学者,我不建议你实现这些功能,因为有些功能在你刚开始的时候是相当复杂的。但是,您可以浏览 post 看看人们在 post 关注什么,并找到更多关于 post.
中提到的事情的信息
我写了一个小程序来测试 c 中的字符串,但我无法理解为什么它在看似不应该的时候起作用,代码是:
#include <stdio.h>
int main() {
char name[5];
printf("Enter your name: ");
scanf("%s",name);
printf("you entered: %s\n",name);
printf("your name is %d letters long\n", strlen(name));
return 0;
}
输入一个 5 个字母的名字,我希望 运行 遇到麻烦,因为我无法将 5 个字符 + 空字符 ender 放入大小为 5 的数组中,但是程序运行正常:
其他答案没有错,但没有完全回答问题。
之所以可行,是因为 c 对内存限制不严格。即使您已经分配了一个长度为 5 的 char 数组,您也可以将其填充到数组末尾之后,c 不会阻止您。
当您将 name
传递给 printf()
时,它只是从数组的开头开始读取内存,直到到达空终止符 [=12=]
。 strlen()
也是一样,只是counts until it reaches the null terminator.
本帖中的其他回答也提到了这一点,但没有提供资源来帮助您更好地理解这个问题。所以,这就是我要做的。
您已经创建了第一个缓冲区溢出错误。这是因为C没有memory safety,也就是说除非用户明确实现,否则对内存的边界没有限制。
在您的例子中,函数 scanf("%s",name);
从用户那里获取数据并将其放入缓冲区。此函数不检查内存边界。这意味着如果输入大小大于分配的缓冲区,则您正在分配的内存之外写入。在许多情况下,它是无害的。然而,它可能是真正难以找到的错误和一些漏洞的来源。关于 buffer overflow 的维基百科文章非常好,并且对所有内容进行了非常详细的解释,这应该可以帮助您更好地理解。
你用来读取字符串长度的函数strlen(name)
,也不做边界检查。如果您查看 strlen 的手册页,您会发现它没有提及任何有关内存边界的内容。相反,它声明它计算字符串开头和下一个终止空字节之间的长度。
The strlen() function calculates the length of the string pointed to by s, excluding the terminating null byte ('[=12=]').
那么,为什么您的应用程序可以运行?
你有一个写时不关心内存边界的函数,你有一个读时不关心内存边界的函数。
如何防止它发生?
幸运的是,您不是第一个遇到此问题的人。如果您有兴趣了解如何防止这种情况发生,我建议您查看此 post How to prevent scanf causing a buffer overflow in C? 。如果你是初学者,我不建议你实现这些功能,因为有些功能在你刚开始的时候是相当复杂的。但是,您可以浏览 post 看看人们在 post 关注什么,并找到更多关于 post.