news 2026/8/24 15:08:00

C语言问题之指针和数组定义和使用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C语言问题之指针和数组定义和使用

一、原始代码错误分析

voiddpi_bit_reverse(chardata_in,char*data_out){inti;for(i=0;i<len(data_in);i++){*data_in[8-i]=data_in[i];}}

存在的主要问题:

  1. data_in 声明为单个 char,却用下标访问,非法。
  2. len() 不是 C 语言函数,应使用 strlen() 或固定长度。
  3. *data_in[8-i] 语法错误(试图对 char 解引用)且下标越界(8-i 超出范围)。
  4. 未使用输出参数 data_out。
  5. 这段代码混淆了"数组倒序"与"位反转",且包含多个 C 语法/逻辑错误。

二、指针与数组下标访问C 语言中,数组名在作为函数参数时会退化为指向首元素的指针。

data_in[i] 完全等价于 *(data_in + i)。

下标操作的本质是:先进行指针偏移(偏移量为 i 个元素),再对偏移后的地址解引用。

data_in[i] 不是对首地址本身取数据,而是对 data_in + i 这个地址取数据。

内存示意(假设字符串 “abc” 存储在地址 0x100~0x102):

表达式 等价形式 实际地址 取值
data_in[0] *(data_in + 0) 0x100 ‘a’
data_in[1] *(data_in + 1) 0x101 ‘b’
data_in[2] *(data_in + 2) 0x102 ‘c’
对于 int 数组,指针偏移量为 sizeof(int)(通常 4 字节),而非 1 字节。

三、字符串结束符 '\0’C 字符串被定义为以空字符 ‘\0’ 结尾的字符序列。

printf(“%s”)、strlen() 等函数依赖 ‘\0’ 确定字符串结束位置。

手动构造字符串(如反转、复制、拼接)后,必须显式添加 ‘\0’。

例如字符串反转函数:

c
void string_reverse(const char *data_in, char *data_out)
{
int n = strlen(data_in);
for (int i = 0; i < n; i++) {
data_out[n - 1 - i] = data_in[i];
}
data_out[n] = ‘\0’; // 必须添加结束符
}
如果不添加 ‘\0’,printf 或 strlen 会继续访问越界内存,导致输出乱码、段错误等未定义行为。

四、空指针检查对指针解引用前必须检查是否为 NULL,否则会引发段错误。

推荐做法:让函数返回状态码,便于调用者判断成功与否。

c
int dpi_bit_reverse(const char *data_in, char *data_out)
{
if (data_in == NULL || data_out == NULL) {
return -1; // 错误码
}
// … 正常逻辑 …
return 0; // 成功
}
若函数返回类型为 void,则应在检测到空指针时直接 return,但调用者无法得知失败原因。更安全的做法是增加缓冲区大小参数,防止溢出。

五、DPI-C 接口与位反转实现5.1 SystemVerilog 导入声明

systemverilog
import “dpi-c” function void dpi_bit_reverse(
input byte data_in,
output byte data_out
);
input byte data_in 对应 C 函数参数 char data_in(标量,按值传递)。

output byte data_out 对应 C 函数参数 char* data_out(指针,用于返回结果)。

返回类型 void 必须与 C 函数一致。

5.2 正确的 C 实现
c
void dpi_bit_reverse(char data_in, char* data_out)
{
if (data_out == NULL) return;

unsigned char in = (unsigned char)data_in; unsigned char out = 0; for (int i = 0; i < 8; i++) { out = (out << 1) | (in & 1); in >>= 1; } *data_out = (char)out;

}
要点:

输入参数是 char,不是指针,不要加 const 或 *。

使用 unsigned char 避免符号扩展干扰位操作。

输出指针需检查 NULL。

5.3 位反转算法示例
输入 0xCA(二进制 11001010),逐步执行:

循环次数 out 更新过程 in 更新过程
1 0 01100101
2 1 00110010
3 2 00011001
4 5 00001100
5 10 00000110
6 20 00000011
7 41 00000001
8 83 00000000
最终 out = 0x53(二进制 01010011),正好是输入的反转。

  1. main 函数与返回类型
    C 程序入口是 main 函数(严格来说之前有启动代码,但用户逻辑从 main 开始)。

C 标准规定 main 必须返回 int,用于向操作系统报告退出状态。

合法形式:

int main(void) { … }

int main(int argc, char *argv[]) { … }

void main 不符合标准,会导致未定义行为,不推荐使用。

返回 0 通常表示成功,非零表示错误。操作系统可通过退出码判断程序执行情况。

  1. 指针初始化与列表赋值
    错误用法
    c
    unsigned char* test_input = {0x00, 0x01, 0x80, 0xca};
    // 编译错误:指针不能直接使用初始化列表赋值
    正确方法
    方法一:先定义数组,再让指针指向它
    c
    unsigned char arr[] = {0x00, 0x01, 0x80, 0xca};
    unsigned char* p = arr;
    方法二:使用复合字面量(C99 及以上)
    c
    unsigned char* p = (unsigned char[]){0x00, 0x01, 0x80, 0xca};
    方法三:动态分配内存并拷贝
    c
    unsigned char init_data[] = {0x00, 0x01, 0x80, 0xca};
    size_t n = sizeof(init_data) / sizeof(init_data[0]);
    unsigned char* p = malloc(n * sizeof(unsigned char));
    memcpy(p, init_data, n * sizeof(unsigned char));
    // 使用后 free§;
    字符串字面量可以直接初始化 const char*,但内容不可修改。

  2. 调试常见错误与修正
    错误示例
    c
    int main() {
    unsigned char in_ = 0xca;
    unsigned char* test_input = {0x00, 0x01, …}; // 错误:指针不能列表初始化
    int test_num = sizeof(test_input) / sizeof(*test_input);
    char ou_;

    for (int i = 0; i < test_num; i++) {
    dpi_bit_reverse(*(test_input+i), &ou_);
    printf(“in: %x, ou: %x”, *(test_input+i), ou_); // 格式问题
    }
    }
    问题:

指针初始化错误,应改为数组。

%x 期望 unsigned int,建议显式转换:(unsigned int)(unsigned char)ou_。

输出缺少换行 \n。

修正后代码
c
#include <stdio.h>

void dpi_bit_reverse(char data_in, char* data_out);

int main(void) {
unsigned char test_input[] = {0x00, 0x01, 0x80, 0xca, 0xff, 0x0f, 0xf0, 0x55, 0xaa};
int test_num = sizeof(test_input) / sizeof(test_input[0]);
printf(“test_num: %d\n”, test_num);

char ou_; for (int i = 0; i < test_num; i++) { dpi_bit_reverse((char)test_input[i], &ou_); printf("in: %02x, ou: %02x\n", (unsigned int)test_input[i], (unsigned int)(unsigned char)ou_); } return 0;

}
9. 总结
指针与数组下标:a[i] 等价于 *(a + i)。

字符串操作必须添加 ‘\0’ 结束符。

函数入口处检查空指针,返回状态码。

DPI-C 函数签名必须严格匹配 SV 导入声明。

位反转用 unsigned char 和循环移位实现。

main 必须返回 int。

指针不能直接用初始化列表赋值,需借助数组或复合字面量。

以上笔记涵盖了对话中讨论的所有关键知识点,可作为 C 语言和 DPI-C 开发的参考。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/24 15:05:34

三维扫描一键变 CAD:Scan2CAD 把家具模型自动摆进真实房间

三维扫描一键变 CAD&#xff1a;Scan2CAD 把家具模型自动摆进真实房间 【免费下载链接】Scan2CAD [CVPR19] Dataset and code used in the research project Scan2CAD: Learning CAD Model Alignment in RGB-D Scans 项目地址: https://gitcode.com/gh_mirrors/sc/Scan2CAD …

作者头像 李华
网站建设 2026/8/24 15:05:05

软件测试面试核心考察维度与高频技术问题解析

1. 软件测试面试的核心考察维度 在软件测试岗位的面试中&#xff0c;面试官通常会从四个核心维度评估候选人的专业能力。理解这些维度不仅能帮助你在面试中有的放矢&#xff0c;更能让你在日常工作中明确提升方向。 1.1 理论基础与概念辨析 扎实的理论基础是测试工程师的立身…

作者头像 李华
网站建设 2026/8/24 15:03:47

集合排序和流排序

import lombok.extern.slf4j.Slf4j;import java.util.Arrays; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.stream.Collectors;/*** HBase工具类&#xff0c;提供数据解析和多列排序功能…

作者头像 李华
网站建设 2026/8/24 15:03:34

【C++ 面试真题】29. 聊聊 C++ 的线程管理(std::thread)

【C 面试真题】聊聊 C 的线程管理&#xff08;std::thread&#xff09;C11 之前想写多线程只能抱 pthread 或 Win32 API&#xff0c;跨平台靠宏&#xff1b;C11 把线程收进了语言标准。背得出"thread 创建线程"只是及格&#xff0c;真考你的是"join 和 detach 不…

作者头像 李华
网站建设 2026/8/24 15:00:13

单片机毕设项目:基于 STM32/51 单片机的4 通道无线病房呼叫液晶显示与语音报警系统设计 主从架构 NRF24L01 病床呼叫终端软硬件设计(020204)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于嵌入式单片机&#xff0c;Java、小程序技术领域和毕业项目实战 ✌️…

作者头像 李华