Microsoft面试问题中此功能有哪些错误?

时间:2010-09-21 09:09:43

标签: c string

我在MS写的访谈中被问到这个问题:

在下面的程序中查找错误,该错误应该返回附加了\n的新字符串。

char* AddnewlinetoString(char *s)
{
  char buffer[1024];
  strcpy(buffer,s);
  buffer[strlen(s)-1] = '\n';
  return buffer;
}

我尝试对自己进行编码,并且能够通过将缓冲区变量设为全局并具有buffer[strlen(s)] = '\n'来实现它。但不知道其中还有很多其他的错误。

12 个答案:

答案 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)

  1. strcpy没有限制,最好使用strncpy。
  2. 您正在复制到静态缓冲区并返回指针。

答案 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;
}