我在MS写的访谈中被问到这个问题:
在下面的程序中查找错误,该错误应该返回附加了\n
的新字符串。
char* AddnewlinetoString(char *s)
{
char buffer[1024];
strcpy(buffer,s);
buffer[strlen(s)-1] = '\n';
return buffer;
}
我尝试对自己进行编码,并且能够通过将缓冲区变量设为全局并具有buffer[strlen(s)] = '\n'
来实现它。但不知道其中还有很多其他的错误。
答案 0 :(得分:55)
我可以看到一些:
未检查输入字符串的长度。
如果strlen(s) > 1023
怎么办?您可以在缓冲区中输入最多1023
的字符串长度。
用
覆盖最后一个字符\n
你用换行符覆盖了最后一个字符。您的\n
应该转到\0
以前的位置,您需要在\0
之后添加新的\n
变量缓冲区是函数的本地函数,您将返回其地址。
缓冲区的内存在堆栈上分配,一旦函数返回,该内存就被释放。
我愿意:
char* AddnewlinetoString(char *s) {
size_t buffLen = strlen(s) + 2; // +1 for '\n' +1 for '\0'
char *buffer = malloc(buffLen);
if(!buffer) {
fprintf(stderr,"Error allocting\n");
exit(1);
}
strcpy(buffer,s);
buffer[buffLen-2] = '\n';
buffer[buffLen-1] = 0;
return buffer;
}
答案 1 :(得分:8)
答案 2 :(得分:8)
这是一个没有错误的C ++版本:
std::string AddnewlinetoString(std::string const& s)
{
return s + "\n";
}
以下是我可能会在C ++ 0x中编写的内容:
std::string AddnewlinetoString(std::string s)
{
return std::move(s += "\n");
}
答案 3 :(得分:6)
我还要补充说,方法的名称应该坚持模式,每个单词应以大写字母开头:
char* AddNewlineToString(char *s)
{
}
PS。感谢Konrad,我已按照您的建议更改了方法名称
答案 4 :(得分:4)
3件事
int len = strlen(s);
char* buffer = (char*) malloc (len + 2); // 1
strcpy(buffer,s);
buffer[len] = '\n'; // 2
buffer[len+1] = '\0'; // 3
return buffer;
编辑:基于评论
答案 5 :(得分:3)
这是一个更正版本(社区wiki,我错过了任何东西)
// caller must free() returned buffer string!
char* AddnewlinetoString(char *s)
{
size_t len;
char * buffer;
if (s == NULL)
s = "";
len = strlen(s);
buffer = malloc(len+2);
if (buffer == NULL)
abort();
strcpy(buffer,s);
buffer[len] = '\n';
buffer[len+1] = 0;
return buffer;
}
正如tony提到的,s可能是一个有效的地址,但仍然是格式错误的c字符串,没有空字节。该函数可能最终会读取,直到它导致段错误或其他可怕的事情。虽然这仍然是惯用的C,但大多数人更喜欢计数字符串(而不是空终止的字符串。)
// caller must free() returned buffer string!
char* AddnewlinetoStringN(char *s, size_t len)
{
char * buffer;
if (s == NULL)
s = "";
buffer = malloc(len+1); // only add 1 byte, since there's no need for the nul
if (buffer == NULL)
abort();
strncpy(buffer,s,len);
buffer[len] = '\n';
return buffer;
}
答案 6 :(得分:3)
此代码的主要问题是它易受stack buffer overflow攻击。这是一个典型的例子。
基本上,输入char *可以超过1024字节;然后,这些额外的字节将覆盖堆栈,允许攻击者修改函数返回指针以指向其恶意代码。然后,您的程序将无意中执行恶意代码。
微软可能需要关注这类漏洞,因为Code Red蠕虫在2001年使用堆栈缓冲区溢出来攻击运行IIS网络服务器软件的数十万台计算机。
答案 7 :(得分:1)
无需返回指针。更改传入指针。
int len = strlen(s);
s[len] = '\n';
s[len + 1] = '\0';
答案 8 :(得分:0)
在C ++中它应该是
std::string AddNewlineToString(const std::string& s) // pass by const reference
{
return s + '\n'; // and let optimizer optimize memory allocations
}
答案 9 :(得分:0)
对于C风格的字符串,它可能是
char* // we want return a mutable string? OK
AddNewlineToString(
const char* s // We don't need to change the original string, so it's const.
)
{
const size_t MAX_SIZE = 1024; // if it's a mutable string,
// it should have a known capacity.
size_t len = strlen(s);
if(len + sizeof("\n") // To avoid the magic number "2".
> MAX_SIZE)
return NULL; // We don't know what to do with this situation,
// the user will check the result and make a decision -
// to log, raise exception, exit(), etc.
// static // We want a thread-safe result
char* buf = new char[1024]; // so we allocate memory in the heap
// and it's C-language-string but not C language :)
memcpy(buf, s, len); // Copy terminating zero, and rewrite it later? NO.
memcpy(buf + len, "\n", sizeof("\n")); // The compiler will do it in one action like
// *(int16_t*)(buf + len) = *(int16_t*)"\n";
// rather than two assignments.
return buf;
}
答案 10 :(得分:0)
使用strdup可以非常简单:
char* AddnewlinetoString(char *s) {
char *buffer = strdup(s);
buffer[strlen(s)-1] = '\n';
return buffer;
}
答案 11 :(得分:-1)
这里有一个更简单的方法:
char* AddnewlinetoString(char *s)
{
char buffer[strlen(s)+1];
snprintf(buffer,strlen(s),"%s\n",s);
return buffer;
}