本篇文章给大家谈谈如何从Golang访问C指针数组,以及golanginterface指针的知识点,同时本文还将给你拓展10、C语言——指针与一维数组(指针数组与数组指针)、73,QT指针数组实战(指
本篇文章给大家谈谈如何从Golang访问C指针数组,以及golang interface 指针的知识点,同时本文还将给你拓展10、C语言 —— 指针与一维数组(指针数组与数组指针)、73,QT指针数组实战(指针数组与数组指针)、C++——指针2-指向数组的指针和指针数组、C/CPP 指针变量 | 数组指针 | 指针数组 | 野指针 | 空指针等相关知识,希望对各位有所帮助,不要忘了收藏本站喔。
本文目录一览:- 如何从Golang访问C指针数组(golang interface 指针)
- 10、C语言 —— 指针与一维数组(指针数组与数组指针)
- 73,QT指针数组实战(指针数组与数组指针)
- C++——指针2-指向数组的指针和指针数组
- C/CPP 指针变量 | 数组指针 | 指针数组 | 野指针 | 空指针
如何从Golang访问C指针数组(golang interface 指针)
我正在使用FFmpeg为Windows平台编写一个应用程序,它是golang包装器goav,但是我在理解如何使用C指针获取对数组的访问方面遇到了麻烦。
我试图获取存储在AVFormatContext类中的流以供使用,并最终将帧添加到OpenGl中的纹理以使视频播放器具有出色的过渡效果。
我认为了解如何转换和访问C数据将使编码变得容易得多。
我已经删除了C代码的所有相关部分,包装程序和我的代码,如下所示:
C代码-libavformat / avformat.h
typedef struct AVFormatContext { unsigned int nb_streams; AVStream **streams; }
Golang Goav包装器
package avutil//#cgo pkg-config: libavformat//#include <libavformat/avformat.h>import "C"import ( "unsafe")type Context C.struct_AVFormatContext;func (ctxt *Context) StreamsGet(i uintptr) *Stream { streams := (**Stream)(unsafe.Pointer(ctxt.streams)); // I think this is where it''s going wrong, I''m brand new to this stuff return (*Stream)(unsafe.Pointer(uintptr(unsafe.Pointer(streams)) + i*unsafe.Sizeof(*streams)));}
我的Golang代码
package mainimport "github.com/giorgisio/goav/avformat"func main() { ctx := &avformat.Context{} // the actual function to initiate this does an mallocz for the streams stream := ctx.StreamsGet(0) //do stuff with stream...}
在C语言中,我似乎只需要执行stream[i],但这行不通,因此我在这里使用了我的问题中的技术为包装器添加了一个函数。但是我没有得到数据。看来我正在获取指向内存中随机位置的指针。那么,如何从golang中访问这些元素?任何资源也将有所帮助;我将为此花很多时间。
答案1
小编典典正如您所注意到的,问题出在以下代码中:
func (ctxt *Context) StreamsGet(i uintptr) *Stream { streams := (**Stream)(unsafe.Pointer(ctxt.streams)); // I think this is where it''s going wrong, I''m brand new to this stuff return (*Stream)(unsafe.Pointer(uintptr(unsafe.Pointer(streams)) + i*unsafe.Sizeof(*streams)));}
在代码中,变量streams
是双指针,因此将offset添加到的结果streams
也是双指针(即类型为**Stream
)。但是,在您的摘录中,它被强制转换*Stream
为不正确的。正确的代码是:
func (ctxt *Context) StreamsGet(i uintptr) *Stream { streams := (**Stream)(unsafe.Pointer(ctxt.streams)) // Add offset i then cast it to **Stream ptrPtr := (**Stream)(unsafe.Pointer(uintptr(unsafe.Pointer(streams)) + i*unsafe.Sizeof(*streams))) return *ptrPtr}
补充说明:
如果要避免在Go
side 进行指针运算,则可以定义一个_辅助_函数,用于访问C端的指针元素(即流),如下所示:
/*void * ptr_at(void **ptr, int idx) { return ptr[idx];}struct AVStream * stream_at(struct AVFormatContext *c, int idx) { if (i >= 0 && i < c->nb_streams) return c->streams[idx]; return NULL;}*/import "C"import ( "unsafe")type Context C.struct_AVFormatContexttype Stream C.struct_AVStreamfunc (ctx *Context) StreamAt(i int) *Stream { p := (*unsafe.Pointer)(unsafe.Pointer(ctx.streams)) ret := C.ptr_at(p, C.int(i)) return (*Stream)(ret)}func (ctx *Context) StreamAt2(i int) *Stream { ret := C.stream_at((*C.struct_AVFormatContext)(ctx), C.int(i)) return (*Stream)(ret)}
您可以选择ptr_at
接受通用(任何)双指针作为其参数的函数,也可以选择stream_at
仅接受指向其的指针作为其参数的更具体的函数AVFormatContext
。:前者的方法可以从任何双指针如用于接入元件AVProgram**
,AVChapter **
等等。后一种方法是优选的,如果我们需要实现额外的处理,如边界检查。
10、C语言 —— 指针与一维数组(指针数组与数组指针)
1、使用指针修改数组元素
int array[2];
int *p;
p = array;
// 或 p = &a[0];
*p = 10;
printf("a[0]=%d\n", a[0]); // 输出:a[0]=10
2、使用指针遍历数组
// a、平常我们是这样遍历数组的
int array[3] = {1, 2, 3};
for(int i=0; i<3; i++) {
printf("a[%d]=%d\n", i, a[i]);
}
// b、用指针可以这样遍历数组
// 如果 p 是指向数组array的首元素array[0]
// 那么 p+1 则会根据数据类型 int 从而指向数组array的第二个元素array[1]
// 在16位编译器环境下,p+1代表增加2个字节
int *p = array;
for(int i=0; i<3; i++) {
printf("a[%d]=%d\n", i, *(p+i));
}
// c、指针遍历2
// 此种方法相比于上一种方法不同的是:上一种方法指针p不变,而这种p每循环一次就改变一个
for(int i=0; i<3; i++) {
printf("a[%d]=%d\n", i, *(p++));
}
// d、指针遍历3
// 数组跟指针有着密不可分的关系,array[i]也可以写成*(array+i)
for(int i=0; i<3; i++) {
printf("a[%d]=%d\n", i, *(array+i));
}
3、指针,数组与函数参数
// 定义一个修改数组首元素的函数
void change(char c[]) {
c[0] = 0;
}
void main() {
char a[3];
change(a); // 传入数组地址
printf("a[0]=%d\n", a[0]); // 输入:a[0]=10
}
// 也可传入指针
void main() {
char a[3];
char *p = a;
change(p); // 传入地址
printf("a[0]=%d\n", a[0]); // 输入:a[0]=10
}
// 当然,change函数还可以改成这样
void change(char *c) {
*c = 10;
// 或c[0] = 10;
}
4、指针数组与数组指针
a、指针数组:int *p[n];
因为优先级:() > [] > *
p首先是一个数组,再由 int * 说明这是一个整型指针数组
即数组里的元素都存放着变量的地址
b、数组指针(行指针):int (*p)[n];
p是一个指针,指向一个整型的一维数组
int a[3][4];
int (*p)[4]; //该语句是定义一个数组指针,指向含4个元素的一维数组。
p=a; //将该二维数组的首地址赋给p,也就是a[0]或&a[0][0]
p++; //该语句执行过后,也就是p=p+1;p跨过行a[0][]指向了行a[1][]
// 所以数组指针也称指向一维数组的指针,亦称行指针。
73,QT指针数组实战(指针数组与数组指针)
1 //指针数组,每一个指针都是一个MainWindow
2 // MainWindow *w[3][4];
3 // for(int i=0;i<3;i++)
4 // {
5 // for(int j=0;j<4;j++)
6 // {
7 // w[i][j] = new MainWindow;
8 // w[i][j]->move(i*100,j*100);
9 // w[i][j]->resize(100,100);
10 // w[i][j]->show();
11 // }
12 // }
13
14 //一个指针指向一个数组指针,这个数组有五列
15 MainWindow *(*w)[5] = new MainWindow* [4][5];
16
17 for(int i=0;i<3;i++)
18 {
19 for(int j=0;j<4;j++)
20 {
21 w[i][j] = new MainWindow;
22 w[i][j]->move(i*100,j*100);
23 w[i][j]->resize(100,100);
24 w[i][j]->show();
25 }
26 }
C++——指针2-指向数组的指针和指针数组
7.4 指向数组元素的指针
声明与赋值
例:int a[10], *pa;
pa=&a[0]; 或 pa=a[p1] ;
通过指针引用数组元素,经过上述声明及赋值后:
*pa就是a[0],*(pa+1)就是a[1],... ,*(pa+i)就是a[i].
a[i], *(pa+i), *(a+i), pa[i]都是等效的。不能写 a++,不能给数组名赋值或者试图改变其值,因为a是数组首地址是常量。
例子:使用三种方法输出数组元素
使用数组名和下标 |
使用数组名指针运算 |
使用指针变量 |
int main() { int a[10]; int i; for(i=0; i<10; i++) cin>>a[i]; cout<<endl; for(i=0; i<10; i++) cout<<a[i];} |
int main() { int a[10]; int i; for(i=0; i<10; i++) cin>>a[i]; cout<<endl; for(i=0; i<10; i++) cout<<*(a+i);} |
int main() { int a[10]; int *p, i; for(i=0; i<10; i++) cin>>a[i]; cout<<endl; for(p=a; p<(a+10); p++) cout<<*p;} |
7.5 指针数组
指针数组的元素是指针型,例如:point *pa[2];由pa[0] ,pa[1]两个指针组成。
#include <iostream>
using namespace std;
int main()
{
int line1[]={1,0,0}; //声明数组,矩阵的第一行
int line2[]={0,1,0}; //声明数组,矩阵的第二行
int line3[]={0,0,1}; //声明数组,矩阵的第三行
int *p_line[3]; //声明整型指针数组
p_line[0]=line1; //初始化指针数组元素
p_line[1]=line2;
p_line[2]=line3;
cout<<"Matrix test:"<<endl; //输出单位矩阵
for(int i=0;i<3;i++) //对指针数组元素循环
{
for(int j=0;j<3;j++) //对矩阵每一行循环
{ cout<<p_line[i][j]<<" "; }
cout<<endl;
}
}
#include <iostream>
using namespace std;
int main()
{
int array2[2][3]={{11,12,13},{21,22,23}}; //声明二维int型数组
for(int i=0;i<2;i++)
{
cout<<*(array2+i)<<endl; //输出二维数组第i行的首地址
for(int j=0;j<3;j++)
{ cout<<*(*(array2+i)+j)<<" "; } //逐个输出二维数组第i行元素值
//写成 { cout<<*array2[i][j]<<" "; }比较好。
cout<<endl;
}
}//输出结果为:
0X0065FDE0
11,12,13
0X0065FDEC
21,22,23
C/CPP 指针变量 | 数组指针 | 指针数组 | 野指针 | 空指针
普通变量和指针变量
共性
PS:
可见这4个函数的汇编指令完全一致,无论是什么类型的指针变量,对指针变量的读写跟普通变量没有任何区别,所谓的指向只是描述指针变量的值时多少而已,就读写而言,指针变量跟普通变量没有任何区别。
特性
普通变量的值常常用于数学计算,而指针变量常常用来定位内存。
普通变量可以不赋初值,但是指针变量的初值必须万分慎重,因为未来的*操纵会以这个初值为目标内存地址,往里面读写数据(可以才C primer plus中看到相应分析)
所以给指针变量赋值一定要是合法合理的内存地址,读取非法的地址程序会修改其他的内存中的值导致程序崩溃,野指针。
空指针和野指针
野指针:定义了一个指针变量,如果没有进行初始化,系统就会有可能随机赋值一个地址给这个指针变量,也就是说,这个指向指向一个未知的区域。
空指针:空指针不是指向常数0,只指向地址0,即NULL,其实换句话说,指针的本质就是地址嘛,空指针就是指针本身的值(地址)为0空指针的作用是防止野指针的出现,因为我们不能知道野指针到底指向哪里,所以我们也无法判断一个指针是否是野指针,这样很危险,但如果养成将指针初始化为空指针的习惯,我们就能判断出这个指针是不是有效的(判断是不是NULL就可以了)通用指针一般都用在函数传参,实现所谓的“多态”,但到函数里面使用时,一般还是被转换成具体类型的指针。
指针变量的+-运算
指针变量的加减运算:也就是做地址偏移,不同 的指针类型偏移的步长不同。
PS:
区分指针数组
int *a[3]
和数组指针int (*a)[3]
,前者时存放指针的数组,后者是指向数组的指针。
指针数组和数组指针
int *b
可以用来定义数组
int a = [1,2,3,4,5];
int *b = a;
int (*b)[5]
用来指向数组
int a = [1,2,3,4,5];
int (*b)[5] = a;
int *b[5]
用来存放指针
int *b[5] =[&a,&b,&c,&d,&e] ;
数组指针(也称行指针)
定义 int (*p)[n];
()优先级高,首先说明p是一个指针,指向一个整型的一维数组,这个一维数组的长度是n,也可以说是p的步长。也就是说执行p+1时,p要跨过n个整型数据的长度。
如要将二维数组赋给一指针,应这样赋值:
int a[3][4];
int (*p)[4]; //该语句是定义一个数组指针,指向含4个元素的一维数组。
p=a; //将该二维数组的首地址赋给p,也就是a[0]或&a[0][0]
p++; //该语句执行过后,也就是p=p+1;p跨过行a[0][]指向了行a[1][]
所以数组指针也称指向一维数组的指针,亦称行指针。
指针数组
定义 int *p[n];
[]优先级高,先与p结合成为一个数组,再由int*说明这是一个整型指针数组,它有n个指针类型的数组元素。这里执行p+1时,则p指向下一个数组元素,这样赋值是错误的:p=a;因为p是个不可知的表示,只存在p[0]、p[1]、p[2]…p[n-1],而且它们分别是指针变量可以用来存放变量地址。但可以这样 p=a; 这里p表示指针数组第一个元素的值,a的首地址的值。
如要将二维数组赋给一指针数组:
int *p[3];
int a[3][4];
p++; //该语句表示p数组指向下一个数组元素。注:此数组每一个元素都是一个指针
for(i=0;i<3;i++)
p[i]=a[i]
这里int *p[3]
表示一个一维数组内存放着三个指针变量,分别是p[0]、p[1]、p[2]
所以要分别赋值。
这样两者的区别就豁然开朗了,数组指针只是一个指针变量,似乎是C语言里专门用来指向二维数组的,它占有内存中一个指针的存储空间。指针数组是多个指针变量,以数组形式存在内存当中,占有多个指针的存储空间。
还需要说明的一点就是,同时用来指向二维数组时,其引用和用数组名引用都是一样的。
比如要表示数组中i行j列一个元素:
*(p[i]+j)、*(*(p+i)+j)、(*(p+i))[j]、p[i][j]
优先级:()>[]>*
数组指针分析:在这里“()”的优先级比“[]”高,“*”号和p2 构成一个指针的定义,指针变量名为p2,int 修饰的是数组的内容,即数组的每个元素。数组在这里并没有名字,是个匿名数组。那现在我们清楚p2 是一个指针,它指向一个包含10 个int 类型数据的数组,即数组指针。
关于如何从Golang访问C指针数组和golang interface 指针的介绍已经告一段落,感谢您的耐心阅读,如果想了解更多关于10、C语言 —— 指针与一维数组(指针数组与数组指针)、73,QT指针数组实战(指针数组与数组指针)、C++——指针2-指向数组的指针和指针数组、C/CPP 指针变量 | 数组指针 | 指针数组 | 野指针 | 空指针的相关信息,请在本站寻找。
本文标签: