今天早上自己写了一段代码,然后测试的时候发现结果总是和预期的不一样,而且偏差的有点离谱,冥思苦想了将近五个小时,最后在我要开始怀疑人生的时候,发现原来是自己犯了一个极其低级但又容易被忽略的问题。好吧,我承认我有点丢程序员的人了。

废话不多说,直接开始用例子来说明吧:

我的代码里有两个结构体,假设为结构体Head和结构体Data,其结构如下:

struct Data{
int a;
char b;
short c;
long d;
}; struct Head{
int fieldcount;
Data fielddata[1];
};

其中,结构体Head包含结构体Data的指针,且fieldcount表示后续有多少Data。我是将这个数据存储在缓冲区中(假设缓冲区为char buf[1024])。当我通过如下代码取数据的时候,发现取出来的数据结构体Data完全不是自己要的:

         Head* h = (Head*) (buf+offset);
size_t datalen = sizeof (Head) + (h->fieldcount-) * sizeof (Data);
offset += datalen; for(size_t i=;i<h->fieldcount;++i)
{
Data* data=(Data*)(h+sizeof(Head)+(i-1)*sizeof(Data));
printf("a: %d b: %c \n", data->a,data->b);
}

不知道大家看出来问题没有,我竟然研究这一段这么简单的代码研究了五个小时,简直丢人啊。直接说问题吧。问题出在这句代码:

 Data* data=(Data*)(h+sizeof(Head)+(i-1)*sizeof(Data));

我的本意是想依次取出来Head后面的data的,即通过Data指针操作内存。可是我却忘记了(指针+偏移量)的含义了。这里的偏移量看起来很正确,是以字节为单位的数,其实对于指针来说,是加了偏移量*sizeof(Head)的字节数,这里的偏移量,意思是加了多少个Head,这也是指针的奇妙之处,也是平时容易忽略的地方。所以每次我读Data的时候,总是读的很靠后面的内存,到时候读的数据存在问题。修改后的代码如下:

 Data* data=(Data*)((char*)h+sizeof(Head)+(i-)*sizeof(Data));

当然,我的环境是在linux上,以utf-8为编码格式,所以char是一个字节,当然这里具体环境可以修改代码。

温馨提示:

在调试代码的时候,还发现一个容易出错的地方,就是注意字节对齐问题。当你把数据存到缓冲区时,如果数据是字节对齐,例如以1字节对齐的时候,如果取得时候没有声明对齐,那会存在意想不到的效果,哈哈聪明的你可以尝试,反正我是尝试过了。

C语言指针加1问题以及字节对齐问题的更多相关文章

  1. c语言指针占几个字节

    指针即为地址,指针几个字节跟语言无关,而是跟系统的寻址能力有关,譬如以前是16为地址,指针即为2个字节,现在一般是32位系统,所以是4个字节,以后64位,则就为8个字节. 可以在自己的电脑上测试下: ...

  2. C语言数组和指针的理解_在取地址运算上的操作_指针加减操作_a 和&a 的区别

    1.一个实例+理论分析 在了解数组和指针的访问方式前提下,下面再看这个例子: main() { int a[5]={1,2,3,4,5}; int *ptr=(int *)(&a+1); pr ...

  3. C语言中的指针加减偏移量

    C语言指针偏移技巧(也是一个要注意的坑) - 陈杰柱的博客 - CSDN博客  https://blog.csdn.net/cjzjolly/article/details/82116772 C语言中 ...

  4. C语言 指针小结

    指针 -->指针变量 类型名 *变量名 int *point1; char *point2; 注意:*p可以直接使用,它代表指针p指向的变量,*p可以当做被指向的变量使用!~~~~ 一个变量的地 ...

  5. iOS学习07之C语言指针

    本次随笔主要是为了学习和理解C语言中的指针,指针树状图如下: 1.访问数据的两种方式 1> 直接访问:定义变量后,直接访问变量 ; printf("a = %d\n", a) ...

  6. 不可或缺 Windows Native (7) - C 语言: 指针

    [源码下载] 不可或缺 Windows Native (7) - C 语言: 指针 作者:webabcd 介绍不可或缺 Windows Native 之 C 语言 指针 示例cPointer.h #i ...

  7. C语言指针学习

    C语言学过好久了,对于其中的指针却没有非常明确的认识,趁着有机会来好好学习一下,总结一下学过的知识,知识来自C语言指针详解一文 一:指针的概念 指针是一个特殊的变量,里面存储的数值是内存里的一个地址. ...

  8. 【C】用我所学去讲C语言指针

    很多人不敢讲C的指针,有些人讲不清,有些人怕讲错.初生牛犊不怕虎,就让我讲讲. 下面开始. 一.指针的定义  指针是内存单元的编号.内存单元是以字节为单位的.所以指针就是字节的编号. 比如我们的个人电 ...

  9. 彻底搞定C语言指针(精华版)

    1.语言中变量的实质 要理解C指针,我认为一定要理解C中“变量”的存储实质, 所以我就从“变量”这个东西开始讲起吧! 先来理解理解内存空间吧!请看下图: 内存地址→ 6 7 8 9 10 11 12 ...

随机推荐

  1. Check whether a + b = c or not after removing all zeroes from a,b and c

    Check whether a + b = c or not after removing all zeroes from a,b and c Given two integers a and b, ...

  2. thinkjs REST API的跨域设置

    用thinkjs也有一小段时间了,和其它国产框架一样,起初是处于观望态度.当然我最先的选择也不是thinkjs而是选的express,用到后面发现实现一个能让自己用着比较顺手的博客还是一件蛮困难或者说 ...

  3. scrapy抓取拉勾网职位信息(七)——数据存储(MongoDB,Mysql,本地CSV)

    上一篇完成了随机UA和随机代理的设置,让爬虫能更稳定的运行,本篇将爬取好的数据进行存储,包括本地文件,关系型数据库(以Mysql为例),非关系型数据库(以MongoDB为例). 实际上我们在编写爬虫r ...

  4. Mybatis 源码分析之一二级缓存

    一级缓存 其实关于 Mybatis 的一级缓存是比较抽象的,并没有什么特别的配置,都是在代码中体现出来的. 当调用 Configuration 的 newExecutor 方法来创建 executor ...

  5. 扩展swap分区

    swap分区在系统的物理内存不够用时,把硬盘的一部分空间释放出来,以供当前运行的程序使用.(临时使用,如果swap分区都不够了还是直接加内存吧) (1).步骤 mkswap /devices(可以是分 ...

  6. TCP/IP——链路层简记

    在TCP/IP协议族中链路层的主要目的有三个: 1,为IP模块发送和接受IP数据报. 2,为ARP模块发送ARP请求和接受ARP应答. 3,为RARP模块发送RARP请求和接受RARP应答. 链路层包 ...

  7. 安装与配置ironic

    安装及配置 由于Ironic的配置很长,下面我们简短的说一下安装和配置过程,具体的安装配置教程参考官方手动配置教程或者使用devstack安装. Ironic需要与Nova.Neutron.Glanc ...

  8. [BZOJ 4071] 巴邻旁之桥

    Link: BZOJ 4071传送门 Solution: 首先算出能提前算的贡献 $K=1$:肯定选中间的点,小学数学 $K=2$:对于每对$(x,y)$一定选离$(x+y)/2$近的桥 也就是说将$ ...

  9. bzoj 3223 文艺平衡树 Splay 打标志

    是NOI2003Editor的一个子任务 #include <cstdio> #include <vector> #define maxn 100010 using names ...

  10. Maven编译代码的相关命令

    第一.main目录下的主代码编写完毕后,使用Maven进行编译,在项目根目录下运行命令mvn clean compile进       行项目编译. 第二.test目录下的测试用例编写完毕之后就可以调 ...