You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何正确打印指针指向的用户输入值?解决UART输入乱码问题

问题描述

尝试打印指针temp指向的键盘输入单字符时出现额外乱码,例如输入“p”会返回p��?4��?。需要解释原因并修改代码,使其仅打印输入的字符。涉及的代码来自ESP-IDF蓝牙BLE SPP客户端示例中的uart_task函数:

void uart_task(void *pvParameters)
{
    uart_event_t event;
    char userInput [20];

    for (;;) {
        //Waiting for UART event.
        if (xQueueReceive(spp_uart_queue, (void * )&event, (TickType_t)portMAX_DELAY)) {
            switch (event.type) {
            //Event of UART receving data
            case UART_DATA:
                if (event.size && (is_connect == true) && (db != NULL) && ((db+SPP_IDX_SPP_DATA_RECV_VAL)->properties & (ESP_GATT_CHAR_PROP_BIT_WRITE_NR | ESP_GATT_CHAR_PROP_BIT_WRITE))) {
                    uint8_t * temp = NULL;
                    temp = (uint8_t *)malloc(sizeof(uint8_t)*event.size);
                    if(temp == NULL){
                        ESP_LOGE(GATTC_TAG, "malloc failed,%s L#%d\n", __func__, __LINE__);
                        break;
                    }
                    memset(temp, 0x0, event.size);
                    sprintf(userInput, "%s", temp);
                    printf("User input ="  "%s" "\n", temp);

uart_read_bytes(UART_NUM_0,temp,event.size,portMAX_DELAY);
                    esp_ble_gattc_write_char( spp_gattc_if,
                                              spp_conn_id, 
                                            (db+SPP_IDX_SPP_DATA_RECV_VAL)->attribute_handle,
                                              event.size,
                                              temp,
                                              ESP_GATT_WRITE_TYPE_RSP,
                                              ESP_GATT_AUTH_REQ_NONE);
                    free(temp);
                }
                break;
            default:
                break;
            }
        }
    }
    vTaskDelete(NULL);
}
原因分析
  • 打印时机错误:printf调用在uart_read_bytes之前,此时temp刚完成内存分配和清零,没有实际读取到用户输入的数据。用%s格式打印时,因为没有字符串结束符\0,printf会持续读取后续内存区域直到遇到\0,导致输出垃圾数据。
  • 缺少字符串结束符:即使读取数据后,temp的内存大小仅为event.size,刚好存输入的字符,没有额外空间存放\0,直接用%s打印依然会越界读取内存。
  • 冗余代码:sprintf(userInput, "%s", temp)完全无用,此时temp是空数据,且后续未使用userInput变量。
修复方案

方案1:添加字符串结束符(推荐)

  1. 将uart_read_bytes移到printf之前,确保打印的是已读取的用户输入。
  2. 分配内存时多申请1字节空间,用于存放字符串结束符\0,避免越界。
  3. 移除无用的sprintf语句。
  4. 读取数据后手动添加\0,保证%s打印正常。

修改后的代码:

void uart_task(void *pvParameters)
{
    uart_event_t event;

    for (;;) {
        // 等待UART事件
        if (xQueueReceive(spp_uart_queue, (void *)&event, (TickType_t)portMAX_DELAY)) {
            switch (event.type) {
            // UART接收数据事件
            case UART_DATA:
                if (event.size && is_connect && db && ((db + SPP_IDX_SPP_DATA_RECV_VAL)->properties & (ESP_GATT_CHAR_PROP_BIT_WRITE_NR | ESP_GATT_CHAR_PROP_BIT_WRITE))) {
                    // 多分配1字节存字符串结束符
                    uint8_t *temp = (uint8_t *)malloc(sizeof(uint8_t) * (event.size + 1));
                    if (!temp) {
                        ESP_LOGE(GATTC_TAG, "malloc failed, %s L#%d\n", __func__, __LINE__);
                        break;
                    }
                    memset(temp, 0x0, event.size + 1); // 初始化包括结束符位置

                    // 先读取UART数据
                    uart_read_bytes(UART_NUM_0, temp, event.size, portMAX_DELAY);
                    // 添加字符串结束符
                    temp[event.size] = '\0';
                    // 打印输入内容
                    printf("User input = %s\n", temp);

                    esp_ble_gattc_write_char(spp_gattc_if,
                                              spp_conn_id,
                                              (db + SPP_IDX_SPP_DATA_RECV_VAL)->attribute_handle,
                                              event.size, // 发送时用原始长度,不需要带结束符
                                              temp,
                                              ESP_GATT_WRITE_TYPE_RSP,
                                              ESP_GATT_AUTH_REQ_NONE);
                    free(temp);
                }
                break;
            default:
                break;
            }
        }
    }
    vTaskDelete(NULL);
}

方案2:指定打印长度(无需修改内存分配)

如果不想额外分配内存,可直接用printf的指定长度格式打印,避免越界读取:

// 读取数据后,替换原printf语句为以下内容
printf("User input = %.*s\n", event.size, temp);

%.*s表示用event.size作为字符串的打印长度,无需添加\0即可正常输出输入内容。

内容的提问来源于stack exchange,提问作者Espcoder88

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 08:34:56