snprintf () в C обрабатывает младшие два байта строки назначения не индивидуально - PullRequest
1 голос
/ 07 октября 2019

Я хотел написать небольшую программу, которая должна переворачивать символы строки с помощью функции 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 character gets appended in front
                                             //of the String "dest" using snprintf() "recursively"
    }
}

Что должна выводить программа: cba
Фактический вывод: ccba

При отладке программы вы можете видеть, чтомладшие два байта (dest[0] и dest[1]) всегда содержат одну и ту же информацию.

Кто-нибудь знает, почему это происходит и как это предотвратить?
Если я не знаюиспользуйте dest дважды в аргументе, но вместо этого используйте временный буфер, такой как: snprintf(temporary, 5, "%c%s", c, dest) и snprintf(dest, 5, "%s", temporary) непосредственно после этого все работает как ожидалось.

Ответы [ 2 ]

5 голосов
/ 07 октября 2019

То, что вы делаете, не допускается стандартом C . Из раздела 7.21.6.5, касающегося функции snprintf:

Функция snprintf эквивалентна fprintf, за исключением того, что выходные данные записываются в массив (заданный аргументом s), а не в поток. Если n равно нулю, ничего не записывается, а s может быть нулевым указателем. В противном случае выходные символы, выходящие за пределы n-1, отбрасываются, а не записываются в массив, и нулевой символ записывается в конце символов, фактически записанных в массив. Если копирование происходит между объектами, которые перекрываются, поведение не определено.

Таким образом, вы не можете назначить пункт назначения одним из источников. Вам нужно записать временную строку.

1 голос
/ 07 октября 2019

Если источник и пункт назначения перекрываются, можно использовать 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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...