Преобразование из char * в int

#c

#c

Вопрос:

Мой код завершается с ошибкой и возвращает действительно большое число:

 #include <stdio.h>

int main()
{
    char *s = "hello123";
    printf("%dn",*(int *)s);
    return 0;
}
  

с atoi он возвращает 0, есть идеи?

Чего я пытаюсь добиться: например, я отправляю «hello123» серверному программному обеспечению, серверное программное обеспечение должно получить числовое значение «123» в строке, делая это следующим методом:

 uint16_t get_uint16(NetworkMessage *message)
{
    uint16_t ret = 0;
    if (!message || !message->buffer)
        return 0;

    ret = *(uint16_t *)(message->buffer   message->position);
    message->position  = sizeof(uint16_t);
    return ret;
}
  

Комментарии:

1. чего вы на самом деле пытаетесь достичь?

2. зачем использовать *(int *)s ? Объясните это.

3. @Mark: пытаюсь получить «123» по позиции в моем сетевом сообщении (в другой программе)

4. Каким был бы ожидаемый результат, если бы строка была «h8llo123»?

5. Я добавил больше информации, пожалуйста, ознакомьтесь с ней (подробнее объясняется)

Ответ №1:

Предполагается, что ваша строка состоит из двух частей: первые индексы содержат символы (например hello ), а последние индексы содержат число (например 123 ). Насколько я понимаю из ваших комментариев, это то, что вы хотели сделать.

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

int main() 
{
     char* s = "hello123";
     char* num_ptr = s;

     while(*num_ptr < '0' || *num_ptr > '9')
            num_ptr;

     int number = atoi(num_ptr);

     printf("%dn", number);
     return 0; 
}
  

После редактирования: попробуйте это? Я предполагаю, message_buffer содержит ваше сообщение и имеет тип char*

 int get_number(char* message_buffer)
{
     char* num_ptr = message_buffer   strlen(message_buffer) - 1;

     while(isdigit(num_ptr) amp;amp; num_ptr > message_buffer)
          --num_ptr;

     int number = atoi(num_ptr);

     if(number > UINT16_RANGE)
          //Handle error here

     return number;     
}


uint16_t get_uint16(NetworkMessage *message) 
{
     uint16_t ret = 0;
     if (!message || !message->buffer)
         return 0;      

     ret = get_number(message->buffer);
     //message->position  = sizeof(uint16_t);     
     return ret; 
} 
  

Комментарии:

1. @Fallen, каково точное содержимое message->buffer ?

2. @Muggen: исправлено, спасибо, я проголосовал за вас и принял ваш ответ!

3. @Fallen, упс, у меня была ошибка в коде. добавьте -1 в strlen() строку, пожалуйста.

4. @Fallen, itoa() возвращает int , но вы используете uint16_t значение, которое может быть меньше, если ваш int 32bit убедитесь, что вы позаботились обо всех условиях ошибки в //Handle error here , которые я добавил.

5. Даже после исправлений (isdigit(*num_ptr) и однократная ошибка в цикле while), get_number(«hello123a4») вернул бы 4, в то время как мой atoi_skip(«hello123a4») вернул бы 123.

Ответ №2:

Ваш код делает не то, что вы думаете. Вы не можете преобразовать текст в число и ожидать, что оно определит, какие числа вы хотите.

Строка — это массив символов, каждый из которых имеет значение ASCII. При приведении к (int*) он принимает значение ASCII первых 4 символов (4 байта для int) и создает из него одно огромное число.

В вашем примере значения ASCII первых 4 символов являются { 0x68, 0x65, 0x6c, 0x6c } . Теперь вы меняете порядок для систем с малым порядковым номером на { 0x6c, 0x6c, 0x65, 0x68 } . Вы объединяете их в 0x6c6c6568 . Преобразование этого значения в десятичное является 1,819,043,176 . Какое число вы получите на выходе.

Если вам нужно только 123, вам нужно использовать умный синтаксический анализ строки, чтобы выделить hello , а затем использовать atoi() для остальных.

Комментарии:

1. Я добавил больше информации в основной пост, ознакомьтесь с ней

Ответ №3:

Вам нужно использовать atoi(s) .

В вашем коде вы преобразуете указатель на строку в указатель на целое число, считывая первые четыре байта строки как некоторое большое целое число. int atoi(char*) произведет надлежащий синтаксический анализ, возвращая целочисленное значение.

Синтаксический анализ «hello123» остановится на первом нечисловом символе и вернет 0. Вы можете пропустить нечисловые символы, тестируя с int isdigit(char) :

 int atoi_skip(char *s) {
        while(*s != '' amp;amp; !isdigit(*s)) s  ; /* skip non digits */
        return atoi(s);
}
  

Ответ №4:

Все остальные абсолютно правы. Вы не можете преобразовать массив символов в целое число с помощью приведения. Это так не работает. В C символы представлены целыми числами. Когда вы пишете:

 char *s = "hello123";
  

То, что вы получаете, — это массив с кучей символов в нем. Вы могли бы эквивалентно написать:

 char *s = {'h', 'e', 'l', 'l', 'o', '1', '2', '3', ''};
  

Таким образом, когда вы вызываете printf("%dn",*(int *)s); , то, что вы делаете, преобразует адрес памяти вашего символьного массива в указатель на целое число. Затем вы берете содержимое этого целого числа и печатаете его. Я почти уверен, что результат, который вы получите, будет зависеть от используемой вами системы, но это определенно не то, что вы хотите.

Что вы, вероятно, хотите сделать, так это:

 printf("%dn", atoi(amp;(s[5]));