
例如:设变量x
for(x=0;x<100;x++)
{
if(a[x]==3)
{
p=&a[x];/找到了x的地址了/
break;
}
}/p要先定义成int p,这样p就指向了此元素地址,当找到x时,退出循环/
scanf("%d",p);/对此元素赋值/
printf("%d",a[x]);
试试吧,看修改值后,输出与输入一不一致,一致就是对了,没有调试,有问题再追问吧。
如果这个数组中有未知个元素都等于3的话,那么要逐一修改值,那么在for语句中把break去掉,把最后的scanf语句移到if的语句中就可以了。
从概念上讲,数据缓冲区在传统方案下是由两个 *** 作创建的:数据缓冲区实体的创建和实际内存的分配。然而事实上,在实际数据变得可用之前,您不需要分配实际的内存 —— 即可以将两个 *** 作分离开来。
最初可以使用内存块的一个空链表来创建一个抽象缓冲区。抽象数据缓冲区仅在实际数据变得可用时才分配内存。释放内存也变成了抽象数据缓冲的责任。考虑到所有这些,集中内存管理和数据复制 *** 作就会带来以下优点:
各方都能通过调用预定义的 API 函数来构造和/或销毁数据缓冲区。 内存使用将保持接近最优状态,因为缓冲区内存仅在必要时才分配,并且会尽快释放,从而最小化内存泄露。 任何一方都不需要知道底层的内存管理方案,使得软件高度可移植,同时保证了交互双方之间的兼容性。 由于没有哪一方需要管理内存,确定缓冲区的大小就变得不必要了(因而也不可能存在前面指出的多次执行问题)。 事实证明缓冲区溢出也不可能会发生,因为仅当存在额外数据空间时才会复制数据。
一种简单的实现
为了表示一个抽象数据缓冲区,需要声明两个结构化的数据类型:
清单 1 声明两个结构化的数据类型来表示一个抽象数据缓冲区 typedef struct BufferBlockHeader_st BufferBlockHeader; struct BufferBlockHeader_st { BufferBlockHeader pNextBlock;}; struct Buffer_st { long int totalLength; BufferBlockHeader pFirstBlock; short int startPoint; BufferBlockHeader pLastBlock; short int endPoint;}; typedef struct Buffer_st Buffer; Buffer 包含关于已创建的抽象缓冲区的信息,它还管理内存块的一个链表:
totalLoength 记录当前存储在缓冲区中的字节数。 pFirstBlock 指向该链表中的第一个内存块。 startPoint 记录第一个内存块中第一个字节的偏移位置。 pLostBlock 指向该链表的最后一个内存块。 endPoint 记录最后一个内存块中第一个空闲字节的偏移位置。
您可以向 Buffer 引入一个附加参数,用以指定每个内存块的大小,并且可以在抽象缓冲区的初始化期间,将该参数设置为一个可取的值。这里假设使用默认块大小。
如果分配了的话, BufferBlockHeader 结构中的 pNextBlock 总是指向该链表中的下一个内存块。每个内存块在分配时都包含一个 BufferBlockHeader 头,后面跟着一个用于存储实际数据的缓冲区块。
图 1 描述了一个存储了一些数据的抽象缓冲区。
图 1 抽象缓冲区的数据结构
M 表示 Buffer 的大小(它通常为 20 字节), B 表示所选择的内存块大小。内存开销大约为 (M+B) 个字节(每个内存块开头的指针忽略不计)。 (M+B) 中的 B 平均起来仅有所使用的第一和最后一个内存块的一半。这个开销几乎保持不变。
在能够缓冲数据之前,必须通过调用下面的 newBuffer() 函数来显式地创建抽象缓冲区:
清单 2 使用 newBuffer() 函数创建抽象缓冲区 Buffer newBuffer() { allocate a Buffer structure; initialize the structure;} 在 清单 2中,该函数分配了包含一个 Buffer 的内存块,并初始化它的条目以指明它是一个空抽象缓冲区。
相应地,必须在使用抽象缓冲区之后通过调用下面的 freeBuffer() 函数来销毁它:
清单 3 使用 freeBuffer() 函数来销毁抽象缓冲区 void freeBuffer(Buffer pBuffer / pointer to the buffer to be freed / ) { while (there is more memory block in the linked list) { free the next memory block; } free the Buffer structure;} 清单 3中的函数释放链表中的所有内存块,然后释放由 newBuffer() 分配的 Buffer 。
要逐步向抽象缓冲区追加数据段,可使用以下函数:
清单 4 逐步向抽象缓冲区追加数据段 long int appendData(Buffer pBuffer, / pointer to the abstract buffer / byte pInput, / pointer to the data source / long int offset, / offset of the input data / long int dataLength / number of bytes of the input data / ) { while (there is more input data) { fill the current memory block; if (there is more input data) { allocate a new memory block and add it into the linked list; } } } 清单 4中的函数把存储在 pInput[offsetoffset+dataLength] 中的字节复制到 pBuffer 所指向的抽象缓冲区中,并在必要时在链表中插入新的内存块,然后返回成功复制到抽象缓冲区中的字节数目。
采用类似的方式,您可以使用以下函数,逐段地从抽象缓冲区读取数据段:
清单 5 从抽象缓冲区读取数据段 long int readData(Buffer pBuffer, / pointer to the abstract buffer / byte pOutput, / pointer to the output byte array / long int offset, / offset of the output byte array / long int arrayLength / size of available output byte array / ) { while (there is something more to read and there is room for output) { read from the first memory block; if (the first memory block is empty) { delete the first memory block from the linked list and free its memory; } }} 在 清单 5 中,该函数销毁性地从 pBuffer 所指向的抽象缓冲区最多读取 arrayLength 个前导字节,并在内存块变为空时从链表中删除它们,然后返回成功读取的字节数目。
如果需要,您可以实现一个类似 readData() 的函数来允许非销毁性的读取。
实现一个函数来返回当前存储在抽象缓冲区中的字节数目,这样可能会带来好处。
清单 6 返回抽象缓冲区中的字节数目 long int bytesAvailable(Buffer pBuffer / pointer to the abstract buffer / ) { return totalLength;}
函数中用到的数据内存看类型,局部变量在栈里,有一个结构来存储这些,包括应该return后栈回到的位置。
堆和栈没那么绝对的区别,都只是内存里的一片,为了使用方便才这么定义的。概念问题。
是取出内存中的数据,不是将内存取出。
取得内存中数据需要该内存的位置,位置一般称为地址;使用存储地址的指针变量就能读取内存中的数据。
只要指针中存在有效地址,而且该指针不是无类型的指针,就可以用这样的格式读写数据
变量=(pointer) //(pointer)= 数值你没在最后添加结束符'\0',修改如下
#include <stdioh>
#include <stdlibh>
int main()
{
char p1,p2,p3;
char p=(char)malloc(1000000);
p1=p;
p2=p;
p3=p2;
gets(p1);
while (p1!='\0')
{
if(p1!=' ')
{
p2=p1;
p2++;
}
p1++;
}
p2='\0'; //加上这一句,添加字符串结束符
puts(p3);
return 0;
}
————————————————————————-
这种输出又不是没用过,没问题的,可以把代码贴上来,我试试
————————————————————————————
输出时用p3啊,
puts(p3);
或用printf也可以
——————————————————————————
汗,你声明一个char p3,处理前让p3=p2不就行了Android系统定义了一个Native窗口 ANativeWindow,结构定义如下:
根据ANativeWindow的结构定义可看出,ANativeWindow描述了本地窗口的基本信息,同时还定义了一系列 *** 作窗口缓冲区的方法,窗口是需要内容显示的,显示的内容自然是存放在窗口缓冲区ANativeWindowBuffer中。
来看下ANativeWindowBuffer窗口缓存的结构定义:
ANativeWindowBuffer定义了窗口缓冲区的基本信息,包括宽,高, stride(每行像素个数),图像格式等,还定义了handle指针,存放Gralloc模块分配的真正的Buffer的地址。
ANativeWindow代表了一个窗口,提供了窗口管理的基本方法来 *** 作窗口缓冲区的出队和入队。ANativeWindowBuffer则负责描述Window一个图形缓冲区。
Surface实现了ANativeWindow, 负责管理一个窗口,而GraphicBuffer则实现了ANativeWindowBuffer,负责管理一个图形缓冲区。Surface后续在进行分析,我们先看下GraphicBuffer的实现。
GraphicBuffer继承自ANativeWindow
GraphicBuffer有三个构造函数
1:创建一个width × height的GraphicBuffer
2:根据已经有的buffer的handle来创建一个GraphicBuffer
3:根据一个ANativeWindowBuffer来创建一个GraphicBuffer
我们只分析第一个看看GraphicBuffer是如何创建的?
构造方法先将GraphicBuffer的width,height等属性设置为默认值0,然后调用initSize来创建Buffer
initSize方法中首先获取了GraphicBufferAllocator对象, GraphicBufferAllocator实现是单例模式,所以每个进程中只有一个GraphicBufferAllocator负责Buffer的分配。
调用GraphicBufferAllocator的alloc方法为当前GraphicBuffer分配了一个指定宽高,以及Format的Buffer, 分配成功后将宽高,stride等属性保存到GraphicBuffer对象的属性中,把buffer的handle保存在GraphicBuffer的handle中,GraphicBuffer就可以管理一个真正的图形缓冲区Buffer,这样GraphicBuffer就创建好了。
GraphicBuffer在构造方法中调用了GraphicBufferAllocator来分配了一个真正的图形缓冲区,具体是怎么分配的呢?
在分析Gralloc模块的时候知道,Gralloc设备会在两个地方被打开,一个是HWCompser,另一个就是GraphicBufferAllocator, 此处会加载Gralloc硬件模块抽象库,同时调用gralloc_open来打开GRALLOC_HARDWARE_GPU0 设备,将返回的alloc_device_t保存在mAllocDev中。
接着看负责缓冲区分配的alloc方法。
alloc方法会调用打开的alloc_device_t设备的alloc方法,GraphicBufferAllocator中调用 mAllocDev->alloc方法会调用到gralloc模块,来分配图形缓冲区,如果分配成功之后则根据返回的属性创建一个alloc_rec_t对象,并将这个对象添加到sAllocList中。
sAllocList是GraphicBufferAllocator维护的一个列表,一个进程中所有分配的图形缓冲区都会维护在这个列表中,只有调用GraphicBufferAllocator的free方法释放缓冲区后,才会从列表中移除。
alloc_device_t设备在打开的过程中会注册 *** 作图形缓冲区的方法,gralloc_alloc和gralloc_free,两个方法分别 用于分配和释放图形缓冲区。
该方法首先根据传入的图像格式计算每个像素占用的字节数,根据每个像素的字节数计算每行像素的个数stride 以及 图形缓冲区所需要的内存大小size。
最后由这些结果作为参数调用gralloc_alloc_buffer来分配缓冲区内存。
gralloc_alloc_buffer分配缓冲区内存做了什么 *** 作呢?
1:根据参数传入的缓冲区大小 创建了一个匿名共享内存,共享内存fd存放到private_handle_t的fd中
2:调用mapBuffer,将共享内存映射到当前进程,并吧内存首地址保存到private_handle_t的base中
3:将private_handle_t返回给调用者,这个就是图形缓冲区的handle, 用于唯一区别一个缓冲区。
至此,Gralloc模块分配缓冲区的逻辑就分析完了
根据传入的图形缓冲区的private_handle_t标识符,调用terminateBuffer来释放buffer, 因我们分析GraphicBuffer的分配与释放,FB设备的相关逻辑暂时不关注。
直接看terminateBuffer是如何释放缓冲区的?
terminateBuffer 释放图形缓冲区很简单,根据private_handle_t的base属性判断内存是否已经映射过了,如果已经映射,则调用munmap方法取消映射即可。
GraphicBuffer实现了ANativeWindowBuffer,用来管理图像窗口的图形缓冲区,是ANativeWindow的显示内容和 *** 作对象,GraphicBuffer的handle指针指向的才是真正的缓冲区内存。
GraphicBufferAllocator负责缓冲区内存的分配,会调用到gralloc模块的gralloc设备进行分配。每个图形缓冲区都是一个匿名共享内存空间,分配的时候创建一个匿名共享内存,然后映射到当前进程,释放的时候将匿名共享内存从当前进程取消映射。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)