2014-11-16 4 views
1

Я написал функцию в c, чтобы преобразовать номер base-10 в его двоичное представление с 16 битами. На выходе этой функции также должно появиться пробел, E.G .: 00000000 00000001 = 1. Само преобразование работает правильно, но мне не удается вернуть это значение в основную строку. Я не получаю никаких ошибок, но после печати sequence_number (по одному символу за раз), я получаю символы ASCII. Я понимаю, что это общий вопрос, но я прочитал много подобных сообщений и не могу определить, что я сделал неправильно.Возвращение строки C из функции в C

void convertToBinary(char *ReturnV, int _this){ 
    //Declare Variables 
    int bin_no[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, bin_Index; 
    int working = _this; 
    int i, c, singleDigit, a; 
    char working_Return[19]; 
    char binaryDigit[1]; 

    for(bin_Index = 15; bin_Index > 0; bin_Index--) {//Conversion 
     working = (working/2); 
     bin_no[bin_Index] = working%2; 
    } 

    for(i = 0; i < 17; i++) {//Convert to string 
     singleDigit = bin_no[i]; 
     sprintf(binaryDigit, "%d", singleDigit); 
     working_Return[i] = binaryDigit[0]; 
    } 

    for(a = 17; a > 9; a--) {//Insert space 
     //Copy all values over 
     working_Return[a+1] = working_Return[a]; 
    } 

    working_Return[9] = ' ';//Insert Space 
    strcpy(ReturnV, working_Return);  
}  

Моя функция вызывается с помощью

int sequenceNumber_Lower = 48; 
char sequence_number[19]; 
convertToBinary(sequence_number, sequenceNumber_Lower); 

, но когда я пытаюсь вывести значения из sequence_number (от основной) с помощью

for(c=0 ; c<18 ; c++) { 
    printf("%c", sequence_number[c]); 
} 

Я получаю случайных символов ASCII. Я проверил, что строка work_Return содержит правильные значения, поэтому ошибка должна заключаться в копировании значений в конце функции. Или я сделал это неправильно, и я пытаюсь распечатать то, что было удалено?

Я знаю, что когда функция заканчивается, локальные переменные уничтожаются, но я чувствую, что сделал это правильно, поскольку я просмотрел многие сообщения здесь и на других сайтах, которые говорят, что это один из действительных способов возврата строки из функции. Можете ли вы помочь мне понять, что я сделал неправильно?

Я попытался возвращающая указатель на эту строку с объявлением функции (и по определению)

char * convertToBinary(int _this); 

Но это были те же самые результаты.

ответ

0

Ваш код имеет две основные проблемы:

используется Sprintf в строке только с одним символом, но Sprintf всегда ставит «\ 0» после того, как последний символ печатной, так что будет перезаписывать память за пределами вашей строки. Это называется переполнением буфера.

Другая проблема в вашем коде заключается в том, что в C все строки, переданные в printf , ДОЛЖНЫ end с '\ 0'. Это маркер «Конец строки», используемый по умолчанию в C. Если ваша строка не указана, функция printf будет продолжать печатать все, что находится в памяти, пока не найдет ее.

Так объявляя

char binaryDigit[2]; 

и в конце добавления:

working_Return[18] = '\0'; 

будет решать ваши проблемы.

Изменения, предложенные в других ответах, также действительны. Например:

'0' + (working & 1) 

намного быстрее, чем sprintf. Запись непосредственно в буфер также намного быстрее.

+0

Спасибо! Обычно я предпочитаю читать языки программирования, прежде чем пытаться их использовать, но мой профессор назначил нам проект на C, и временные рамки этого не позволяли. –

1

Это ваш код после того, как несколько исправлений (descibed ниже):

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

void convertToBinary(char *ReturnV, int _this){ 
    int bin_no[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, bin_Index; 
    int working = _this; 
    int i, singleDigit, a; 
    char binaryDigit[1]; 

    for(bin_Index = 15; bin_Index >= 0; bin_Index--) { 
     working = (working/2); 
     bin_no[bin_Index] = working%2; 
    } 

    for(i = 0; i < 18; i++) { 
     if(i<=7) 
      ReturnV[i] = (char)(((int)'0')+bin_no[i]); 
     else if(i==8) 
      ReturnV[8] = ' '; 
     else 
      ReturnV[i] = (char)(((int)'0')+bin_no[i+1]); 
    } 
    ReturnV[17] = '\0'; 
}  

int main() { 
    int sequenceNumber_Lower = 48; 
    char sequence_number[18]; 
    convertToBinary(sequence_number, sequenceNumber_Lower); 
    printf("%s\n", sequence_number); 
} 

Исправление:

  1. Вместо использования sprintf() используйте (char)(((int)'0')+bin_no[i]) для преобразования int в char.
  2. Сохраните непосредственно строку ReturnV, тем самым избегая необходимости создавать другую строку.
  3. Выделять массивы только до тех пор, пока они вам понадобятся.
  4. Добавить \0 в конце.
0

Существует ряд ошибок и некоторые недостатки. В основном, число итераций цикла немного беспорядочно, а оператор sprintf() пишет целое число в виде текста в строку длиной всего 1 символ - это никогда не будет работать.

Неэффективность заключается в том, что вы можете напрямую использовать аргументы функции. int _this может использоваться точно так же, как локальная переменная int working. Вы также можете записать свой результат непосредственно в строку char *ReturnV (при условии, что она достаточно длинная).

#include <stdio.h> 
#include <string.h> 

void convertToBinary(char *ReturnV, int working){ 
    int bin_Index;     // remove most of the vars 
    for (bin_Index = 16; bin_Index > 0; bin_Index--) { // skip 1st string char 
     ReturnV[bin_Index] = '0' + (working & 1);  // ascii text 
     working >>= 1; 
    } 
    ReturnV [17] = 0;     // terminate string 
    strncpy(ReturnV, ReturnV+1, 8); // create a gap 
    ReturnV [8] = ' ';    // Insert Space 
}  

int main() { 
    int sequenceNumber_Lower = 48; 
    char sequence_number[19]; 
    convertToBinary(sequence_number, sequenceNumber_Lower); 
    printf("%s", sequence_number); 
    return 0; 
} 
+0

Использование strncpy в области перекрывающейся памяти имеет неопределенное поведение. Например: http://www.gnu.org/software/libc/manual/html_node/Copying-and-Concatenation.html – Governa

+0

Я могу понять, что если байты назначения будут перезаписывать исходные байты по мере продолжения копирования, но они не «т. Однако я считаю, что 'memmove()' было бы лучше. –

0

В дополнении к другим проблемам, вы не null-terminating ваша рабочая строка перед strcpy, Вы должны помнить ВСЕГДА инициализируйте ПЕРЕМЕННЫЕ И ПРЕКРАТИТЬ ВАШ Шнуры:

char working_Return[19]; 

должен быть:

char working_Return[19] = {0}; 

Это будет null-terminate вашей рабочей строкой (то есть '0' после любого символа, помещенного в строку, начинающуюся с working_Return[0] вплоть до working_Return[18]), если вы не перезапишете его, и он позволит strcpy найти конец строки (предотвращая все эти funny символов). Что касается двоичного преобразования, есть несколько способов приблизиться к нему. Один из моих любимых является:

#include <stdio.h> 

/** returns pointer to formatted binary representation of 'n' zero padded to 'dsz'. 
* returns pointer to string contianing formatted binary representation of 
* unsigned 64-bit (or less) value zero padded to 'dsz' digits with char 
* 'sep' placed every 'gsz' digits. (e.g. 10001010 -> 1000-1010). 
*/ 
char *fmt_binstr (unsigned long n, unsigned char dsz, unsigned char gsz, char sep) { 

    static char s[128 + 1] = {0}; 
    char *p = s + 128; 
    unsigned char i; 

    for (i = 0; i < dsz; i++) { 
     p--; 
     if (i > 0 && gsz > 0 && i % gsz == 0) 
      *p-- = sep; 
     *p = (n >> i & 1) ? '1' : '0'; 
    } 

    return p; 
} 

int main() { 

    printf ("\n Usage:\n\n char *fmt_binstr (unsigned long number,\n\t\t unsigned char display_size,\n\t\t unsigned char grouping_size,\n\t\t char group_seperator)\n\n"); 
    printf ("\nExample of formatted binary strings\n\n"); 
    printf (" fmt_binstr (253, 8, 0, 0)   : %s\n", fmt_binstr (253, 8, 0, 0)); 
    printf (" fmt_binstr (253, 8, 2, '-')   : %s\n", fmt_binstr (253, 8, 2, '-')); 
    printf (" fmt_binstr (253, 8, 4, '-')   : %s\n", fmt_binstr (253, 8, 4, '-')); 
    printf (" fmt_binstr (253, 16, 4, '-')   : %s\n", fmt_binstr (253, 16, 4, '-')); 
    printf (" fmt_binstr (253, 16, 2, ':')   : %s\n\n", fmt_binstr (253, 16, 2, ':')); 

    printf (" fmt_binstr (0xbeefcafe, 32, 0, 0) : %s\n", fmt_binstr (0xbeefcafe, 32, 0, 0)); 
    printf (" fmt_binstr (0xbeefcafe, 32, 8, '-') : %s\n", fmt_binstr (0xbeefcafe, 32, 8, '-')); 
    printf (" fmt_binstr (0xbeefcafe, 32, 4, '-') : %s\n\n", fmt_binstr (0xbeefcafe, 32, 4, '-')); 

    return 0; 
} 

выход:

$ ./bin/prnbin 

    Usage: 

    char *fmt_binstr (unsigned long number, 
        unsigned char display_size, 
        unsigned char grouping_size, 
        char group_seperator) 


Example of formatted binary strings 

    fmt_binstr (253, 8, 0, 0)   : 11111101 
    fmt_binstr (253, 8, 2, '-')   : 11-11-11-01 
    fmt_binstr (253, 8, 4, '-')   : 1111-1101 
    fmt_binstr (253, 16, 4, '-')   : 0000-0000-1111-1101 
    fmt_binstr (253, 16, 2, ':')   : 00:00:00:00:11:11:11:01 

    fmt_binstr (0xbeefcafe, 32, 0, 0) : 10111110111011111100101011111110 
    fmt_binstr (0xbeefcafe, 32, 8, '-') : 10111110-11101111-11001010-11111110 
    fmt_binstr (0xbeefcafe, 32, 4, '-') : 1011-1110-1110-1111-1100-1010-1111-1110 

Вы можете использовать 64-bit значения, а также (только немного времени для примера).