Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/56.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 我可以确定char*参数寻址的有效内存量吗?_C++_C - Fatal编程技术网

C++ 我可以确定char*参数寻址的有效内存量吗?

C++ 我可以确定char*参数寻址的有效内存量吗?,c++,c,C++,C,我有一个类似于: // string is a null-terminated char array. Replace all a in the string with b void ReplaceCharInString(char *string, char a, char b) { // loop over the string char by char, to find all "a"s and replace them with "b" } 我在做防守程序。问题是,客户端上的实现答复实

我有一个类似于:

// string is a null-terminated char array. Replace all a in the string with b
void ReplaceCharInString(char *string, char a, char b)
{
// loop over the string char by char, to find all "a"s and replace them with "b"
}

我在做防守程序。问题是,客户端上的实现答复实际上传递了一个字符数组。如果传入单个字符的地址,则程序肯定会进入错误状态(可能会崩溃)。我如何检查和避免这种情况?(我知道如果我传入std::string对象,问题当然就解决了)

否,您不能检查这一点,必须信任函数的用户传递一个实际的正确以null结尾的字符串


这也是所有C标准库函数的方式,如
strcpy()
strlen()
。。。工作。

最好使用std::string

函数只获取指向内存中某个位置的指针。防御性编程实践是检查它是否为NULL。如果调用者“忘记”分配内存或某些分配失败,则此值通常为

可能会对无效字符数组进行更多检查,但这些检查取决于平台


至少您无法区分指向字符数组的指针和指向字符的指针。

您的原型是错误的。将数组传递给函数时,始终必须传递数组的长度,因为在函数内部,您永远不知道数组的大小(它始终是指针的大小)。因此,您应该为数组的大小声明一个int变量,以便声明本身能够显式地使用数组

void ReplaceCharInString(char *string, int len, char a, char b)
这样,您就不需要读取字符串输入arg的最大空字符,而只需要使用长度。
如果你不能做到这一点,并且你必须保持声明的原样,那么你应该就函数的用户应该做什么有一个明确的合同,以避免出现问题。然后,将履行合同的责任委托给函数的调用方。你真的不能相信用户输入的数据。使用
std::string
是一种改进,因为它可以防止缓冲区溢出,但仍然不是完全安全的。如何阻止用户输入消耗您所有内存的10GB字符串

您确实需要在第一次从用户接收输入时验证输入(无论是来自套接字还是通过stdin)。例如,您可以强制执行要读取的最大字节数,或者确保所有输入字符都在ASCII范围内


如果必须使用C字符串,可以将输入缓冲区设置为0,并确保缓冲区中的最后一个字符始终为空字节,以确保字符串正确以空结尾。

否如果字符串未以空结尾,则无法检查分配的内存是否已用完。
正如sth所说,C标准库函数(如strcpy()、strlen())也依赖于字符串有效(以null结尾)这一事实

。。。然而,一种解决方案是挡泥板。成本很高(就成本而言),且仅对GCC有效
是一个为所有指针/数组操作提供指令的库。有了它,您将能够检查特定位置是否为有效内存


事实上,我认为使用Mudflap的唯一原因是,对于您的应用程序来说,安全性是一个非常大的问题。但即使在这种情况下,GCC也提供了一种更好的方法来防止缓冲区溢出(请参阅-fstack protector[-all])。

通过正确记录代码来避免这种情况。除了C语言的初学者(不应该编写严肃的代码)之外,没有人会使用单个
char
变量的地址(甚至声明这样的变量),因此您的恐惧与此无关

C99中部分防止这种情况的一种方法是将函数声明为:

void ReplaceCharInString(char string[static 2], char a, char b);
这意味着
string
必须是指向至少2个字符的有效指针,这将防止您提到的单字符指针问题,代价是使函数无法支持空字符串。但它仍然无法保护您免受不正确的
malloc
等的影响


编写安全的C实际上是一个适当的代码文档和审计问题,以及解雇不称职的人(或者更好的是,从一开始就不要雇用他们)。这种语言设计得轻巧高效。如果你试图把你自己的巨大安全带层放在上面,你可能会比设计更高级语言的人做的更差,然后你也可以用更高级的语言来开始。

< P>用C++,您应该使用函数重载,并确保没有人会向您发送字符的地址

void ReplaceCharInString(std::string & p_string, char p_a, char p_b)
{
   for(size_t i = 0, iMax = p_string.size(); i < iMax; ++i)
   {
      // replace if needed : p_string[i]
   }
}

void ReplaceCharInString(char & p_char, char p_a, char p_b)
{
   // replace if needed : p_char
}

template<size_t size>
void ReplaceCharInString(char (& p_string)[size], char p_a, char p_b) ;
{
   for(size_t i = 0; i < size; ++i)
   {
      // replace if needed : p_string[i]
   }
}
所以不可能有人用一个字符的地址调用你的函数


< >无论如何,在C++中,很少有理由使用<代码> char */COD>作为字符串(您将使用一个“代码> STD::String ”,甚至更少的<代码> char */COD>作为单个字符的地址(您将使用的是“代码> char和< /代码>”)因此,没有人会抱怨上述函数中缺少对
char*
的支持。

尽管只要您只将单个字符替换为另一个单个字符并在null处停止,您就不需要长度。@Roger:从文章中,他希望开始读取arg字符串直到NULL终止字符。如果用户传入单个字符的地址,如果他这样做(即开始读取到NULL),他将得到一个mem损坏。通过使用length,他不需要依赖于空字符,并且已明确通知调用方函数需要一个数组。如果缓冲区的长度由客户端提供(以及可能可疑的数据),则提供该长度没有帮助@user:如果调用方传入一个长度为1的字符,而不是在(c==a)c=b时执行
,那将是愚蠢的
@CodeButcher:你有一个观点。但是在函数中,不可能使用sizeof来获得传递数组的大小。传递长度是标准的。如果
void foo()
{
   char         a[4] ;
   std::string  b  ;
   char         c  ;
   char *       d ;

   // initialize a, b, c and d to some values

   ReplaceCharInString(a, 'x', 'z') ; // compiles
   ReplaceCharInString(b, 'x', 'z') ; // compiles
   ReplaceCharInString(c, 'x', 'z') ; // compiles
   ReplaceCharInString(d, 'x', 'z') ; // COMPILATION ERROR
}