C中的snprintf()不单独处理目标字符串的最低两个字节
我想写一个小程序,用下面的方法使用snprintf函数反转字符串中的字符。在那里我注意到了一些奇怪的事情C中的snprintf()不单独处理目标字符串的最低两个字节,c,string,pointers,printf,C,String,Pointers,Printf,我想写一个小程序,用下面的方法使用snprintf函数反转字符串中的字符。在那里我注意到了一些奇怪的事情 int main() { char dest[5] = ""; char source[5] = "abc"; for (int i = 0; i < 4; i++) { char c = source[i]; snprintf(dest, 5, "%c%s", c, dest); //here, the current
int main() {
char dest[5] = "";
char source[5] = "abc";
for (int i = 0; i < 4; i++) {
char c = source[i];
snprintf(dest, 5, "%c%s", c, dest); //here, the current character gets appended in front
//of the String "dest" using snprintf() "recursively"
}
}
程序应输出的内容:cba
实际产量:中华公所
调试程序时,您可以看到最低的两个字节dest[0]和dest[1]始终携带相同的信息
有人知道为什么会发生这种情况以及如何预防吗?
如果我在参数中不使用dest两次,而是使用一个临时缓冲区,如:snprintfetemporal,5,%c%s,c,dest和snprintfdest,5,%s,temporary,然后直接使用,一切都会按预期工作。您所做的是不被允许的。根据第7.21.6.5节关于snprintf功能的内容: snprintf函数等同于fprintf,只是 输出被写入参数s指定的数组,而不是 去小溪。如果n为零,则不写入任何内容,s可能为null 指针。否则,超过n-1的输出字符将被删除 丢弃而不是写入数组,以及空字符 在实际写入的字符末尾写入 阵列。如果复制发生在重叠的对象之间, 该行为未定义
所以你不能让目的地成为来源之一。您需要写入临时字符串。系统不允许您这样做。根据第7.21.6.5节关于snprintf功能的内容: snprintf函数等同于fprintf,只是 输出被写入参数s指定的数组,而不是 去小溪。如果n为零,则不写入任何内容,s可能为null 指针。否则,超过n-1的输出字符将被删除 丢弃而不是写入数组,以及空字符 在实际写入的字符末尾写入 阵列。如果复制发生在重叠的对象之间, 该行为未定义
所以你不能让目的地成为来源之一。您需要写入临时字符串。如果源和目标重叠,可以使用memmove
#include <stdio.h>
#include <string.h>
int main(){
char dest[5] = "";
char source[5] = "abc";
size_t len = strlen ( source);
for ( size_t i = 0; i < len; i++) {
memmove ( &dest[1], &dest[0], len);//move len bytes in array of [5]
dest[0] = source[i];//set first byte
dest[len] = 0;//ensure zero terminator
printf ( "%s\n", dest);
}
}
如果需要递归,则可以使用它
#include <stdio.h>
size_t strreverse(char *str, size_t index, char *dest) {
char ch = str[index];
if(str[index] =='\0') {
return 0;
}
index = strreverse ( str, index + 1, dest);//recursion
dest[index] = ch;
return index + 1;
}
int main ( void) {
char text[] = "abc";
char result[sizeof text] = "";
strreverse ( text, 0, result);
printf("%s\n", text);
printf("%s\n", result);
return 0;
}
如果源和目标重叠,则可以使用memmove
#include <stdio.h>
#include <string.h>
int main(){
char dest[5] = "";
char source[5] = "abc";
size_t len = strlen ( source);
for ( size_t i = 0; i < len; i++) {
memmove ( &dest[1], &dest[0], len);//move len bytes in array of [5]
dest[0] = source[i];//set first byte
dest[len] = 0;//ensure zero terminator
printf ( "%s\n", dest);
}
}
如果需要递归,则可以使用它
#include <stdio.h>
size_t strreverse(char *str, size_t index, char *dest) {
char ch = str[index];
if(str[index] =='\0') {
return 0;
}
index = strreverse ( str, index + 1, dest);//recursion
dest[index] = ch;
return index + 1;
}
int main ( void) {
char text[] = "abc";
char result[sizeof text] = "";
strreverse ( text, 0, result);
printf("%s\n", text);
printf("%s\n", result);
return 0;
}
不能将字符串打印到自身:如果dest是第一个参数,即要打印到的字符串,则不能将其用作格式后面的任何参数。对于int i=0;i<4;i++将abc中的nul字节读取为c,然后在snprintfdest,5,%c%s,c,dest;中的字符串前面加上前缀;。是的,正如@MOehm所指出的,如果字符串重叠,则调用未定义的行为,或者递归地误用该词。您的代码与递归无关。您不能将字符串打印到自身:如果dest是第一个参数,即您要打印到的字符串,则不能将其用作格式后面的任何参数。对于int i=0;i<4;i++将abc中的nul字节读取为c,然后在snprintfdest,5,%c%s,c,dest;中的字符串前面加上前缀;。是的,正如@MOehm所指出的,如果字符串重叠,则调用未定义的行为,或者递归地误用该词。您的代码与递归无关。