Reputation: 391
I have the below program:(functionality: pads white spaces to the right of string,used astreix here for visual ease):
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;
}
There seems to be an issue at memset when I look at the value post memeset, it looks very incorrect i.e junk why is this?In the end I null terminate the string yet I see junk value and a stack corruption error, not sure what's wrong with my logic.
(I have attached a snapshot of the same)
Upvotes: 0
Views: 844
Reputation: 153303
@Harry Johnston fine answer explains what went wrong.
To pad a string to its array size, recommend:
1) Dispense with the excessive writing of '\0'
(memset(buff, ...);... strncpy_s(buff,...
) that are subsequently written with data.
2) Use size_t
for indexing arrays and string math. size_t
is the right size integer for the job.
3) Watch out for badly form calls like with a pad longer than the target or a call with a size of 0. Could check for NULL
pointers too.
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);
Upvotes: 2
Reputation: 36308
The unexpected behaviour can be seen in this simpler example:
#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;
}
The output is 254 rather than 0, but only in a debug build. This happens during the call to strncpy_s
, which is unexpectedly writing to the destination buffer past the end of the copy, presumably in order to expose bugs such as the one (already pointed out) in your code.
NB: Retired Ninja quite correctly points out (in the comments to the question) that this is described, slightly inaccurately, in the documentation's fine print, which I'd originally overlooked:
The debug versions of these functions first fill the buffer with 0xFD. To disable this behavior, use _CrtSetDebugFillThreshold.
(In fact, in Visual Studio 2010, at least, it fills the buffer with 0xFE.)
Upvotes: 3