我有以下程序:(功能:填充字符串右侧的空格,在这里使用astreix以方便视觉):
os:windows(visual studio)
#include "stdafx.h"
#include<stdlib.h>
#include<string.h>
#define CBUFFSIZE 48
void right_pad_str(char *pad_str, char *buff,int max_buffsize){
int padstr_len = 0;
int space_len = 0;
char *end_str = NULL;
memset(buff, '\0', max_buffsize);
padstr_len = strlen(pad_str);
space_len = ((max_buffsize - 1) - padstr_len);
strncpy_s(buff, max_buffsize, pad_str, strlen(pad_str));
end_str = buff +padstr_len;
memset((end_str), '*', space_len);
buff[max_buffsize] = '\0';
}
int _tmain(int argc, _TCHAR* argv[]){
char tmpstr[49] = { '\0' };
char *str = "hello_world";
right_pad_str(str, tmpstr, CBUFFSIZE + 1);
return 0;
}
当我查看memeset的值时,memset上似乎存在一个问题,它看起来非常不正确,即垃圾为什么会这样?最后我null终止字符串但我看到垃圾值和堆栈损坏错误,而不是确定我的逻辑有什么问题。
(我附上了相同的快照)
答案 0 :(得分:3)
在这个更简单的例子中可以看到意外的行为:
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
char buffer[3];
buffer[0] = '\0';
buffer[1] = '\0';
buffer[2] = '\0';
strncpy_s(buffer, 3, "*", 1);
printf("%u\n", (unsigned int)(unsigned char)buffer[2]);
return 0;
}
输出为254而不是0,但仅在调试版本中。这种情况发生在调用strncpy_s
期间,这意外地在副本结束时写入目标缓冲区,可能是为了暴露代码中的错误(已经指出过)。
NB:退休忍者非常正确地指出(在问题的评论中)这个描述略微不准确,在the documentation's细则中,我原先忽略了这一点:
这些函数的调试版本首先使用0xFD填充缓冲区。要禁用此行为,请使用_CrtSetDebugFillThreshold。
(事实上,至少在Visual Studio 2010中,它用0xFE填充缓冲区。)
答案 1 :(得分:2)
@Harry Johnston很好的答案解释了出了什么问题。
要将字符串填充到其数组大小,建议:
1)随着'\0'
(memset(buff, ...);... strncpy_s(buff,...
)的过度写作而随后写入数据。
2)使用size_t
索引数组和 string 数学。 size_t
是作业的正确大小整数。
3)注意糟糕的表单调用,比如使用长度超过目标的pad或者调用大小为0的调用。也可以检查NULL
指针。
void right_pad_str(const char *pad_str, char *buff, size_t buff_size){
if (buff_size > 0) {
size_t pad_size = strlen(pad_str) + 1;
if (pad_size > buff_size) {
pad_size = buff_size;
}
memcpy(buff, pad_str, pad_size - 1);
memset(&buff[pad_size - 1], '*', buff_size - pad_size);
buff[buff_size - 1] = '\0';
}
}
// usage
right_pad_str(str, tmpstr, sizeof tmpstr);