C语言中通过指针访问char数组仅能获取首字符的问题
C语言指针传递数组后函数内仅能访问第一个字符的问题分析与修复
问题描述
将C语言char数组通过指针传递给函数后,函数内访问该数组时仅能获取第一个字符,其余内容均为随机字节,但调用函数前所有变量状态正常,参考相关方案后问题仍未解决。以下是原代码及运行输出:
原代码
#include <stdio.h> #include <string.h> #include <stdint.h> void hex_to_bytes(char *hex, char **bytes, size_t *bytes_len) { int length = strlen(hex) % 2? strlen(hex) + 1 : strlen(hex); unsigned char checkedHex[length]; for (int i = 0; i <= length; i++) { if (i == 0 && strlen(hex) % 2){ checkedHex[0] = '0'; } else if (i == length){ checkedHex[i] = '\x00'; } else { checkedHex[i] = hex[i]; } } *bytes_len = length / 2; int counter = 0; for (int i = 0; i < length / 2; i++){ sscanf(&checkedHex[counter], "%2hhx", &bytes[i]); counter += 2; } } void *b64_encode(unsigned char *bytes, size_t bytes_len) { printf("in b64_encode %p\n", bytes); printf("bytes = %s\n", &bytes[48]); printf("0x"); for (int i = 0; i < bytes_len; i++) { printf("%02X", bytes[i]); } printf("\n"); } int main() { unsigned char hex[] = "49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d"; unsigned char *bytes[48] = {0}; size_t bytes_len = 0; hex_to_bytes(hex, (unsigned char **) &bytes, &bytes_len); printf("in main %p\n", &bytes); printf("bytes = %s\n", &bytes[48]); unsigned char *base64 = b64_encode(bytes, bytes_len); return 1; }
原运行输出
in main 0x7ff7b0ef1350 bytes = 49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d in b64_encode 0x7ff7b0ef1350 bytes = l 0x490000000000000027000000000000006D0000000000000020000000000000006B000000000000006900000000000000
问题根源分析
- 变量类型定义错误:
main函数中unsigned char *bytes[48]是指针数组(每个元素是unsigned char*类型),但实际需要的是存储转换后字节的字符数组,类型不匹配导致后续内存操作完全偏离预期。 - 强制转换导致内存操作异常:调用
hex_to_bytes时将字符数组地址强制转为unsigned char**,函数内&bytes[i]实际操作的是指针数组元素(64位系统下每个元素占8字节),因此输出出现大量填充的00。 - 数组越界访问:
hex_to_bytes中checkedHex数组长度为length,但循环条件i <= length会访问checkedHex[length],超出合法下标范围(0~length-1),触发未定义行为。 - 函数参数传递错误:调用
b64_encode时传递指针数组bytes,但函数期望的是unsigned char*类型的字节数组指针,类型不匹配导致访问异常。
修复后的代码
#include <stdio.h> #include <string.h> #include <stdint.h> void hex_to_bytes(char *hex, unsigned char *bytes, size_t *bytes_len) { int hex_len = strlen(hex); int length = hex_len % 2 ? hex_len + 1 : hex_len; // 定义足够长度的数组存储补0后的十六进制字符串,包含终止符 unsigned char checkedHex[length + 1] = {0}; if (hex_len % 2) { checkedHex[0] = '0'; memcpy(checkedHex + 1, hex, hex_len); } else { memcpy(checkedHex, hex, hex_len); } *bytes_len = length / 2; int counter = 0; for (int i = 0; i < *bytes_len; i++) { sscanf(&checkedHex[counter], "%2hhx", &bytes[i]); counter += 2; } } void *b64_encode(unsigned char *bytes, size_t bytes_len) { printf("in b64_encode %p\n", bytes); // 字节数组不是字符串,直接用%s输出会因终止符提前结束,改为打印单个字节的十六进制值 printf("bytes[48] = 0x%02X\n", bytes[48]); printf("0x"); for (int i = 0; i < bytes_len; i++) { printf("%02X", bytes[i]); } printf("\n"); return NULL; // 补充返回值避免编译警告 } int main() { unsigned char hex[] = "49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d"; // 定义字符数组存储转换后的字节,长度足够容纳结果 unsigned char bytes[48] = {0}; size_t bytes_len = 0; // 直接传递字节数组地址,无需强制转换 hex_to_bytes((char*)hex, bytes, &bytes_len); printf("in main %p\n", bytes); printf("bytes[48] = 0x%02X\n", bytes[48]); unsigned char *base64 = b64_encode(bytes, bytes_len); return 0; }
关键修改说明
- 将
main中的unsigned char *bytes[48]改为unsigned char bytes[48],定义为字节数组而非指针数组。 - 修改
hex_to_bytes的参数类型为unsigned char *bytes,直接接收字节数组指针,删除不必要的二级指针和强制转换。 - 修复
checkedHex的数组越界问题,定义长度为length+1并初始化,用memcpy替代手动循环复制,避免错误。 - 修正
b64_encode中字节数组的输出方式,字节数组不是字符串,不能直接用%s输出,改为打印单个字节的十六进制值。 - 补充
b64_encode的返回值,避免编译警告。
内容的提问来源于stack exchange,提问作者John554
相关产品推荐
相关产品推荐

