在exmaples\darknet.c中找到主函数main
其中有不少二级指针,参考https://m.imooc.com/article/30475
char **s;
char **为二级指针, s保存一级指针 char *的地址,关于二级指针就在这里不详细讨论了 ,简单的说一下二级指针的易错点。
举例:
char *a [ ] = {"China","French","America","German"};
char **s = a;
为什么能把 a赋给s,因为数组名a代表数组元素内存单元的首地址,即 a = &a[0] = 0012FF38;
而 0x12FF38即 a[0]中保存的又是 00422FB8 ,这个地址, 00422FB8为字符串"China"的首地址。
即 *s = 00422FB8 = "China";
这样便可以通过s 操作 a 中的数据
printf("%s",*s);
printf("%s",a[0]);
printf("%s",*a);
都是一样的。。。
但还是要注意,不能a = s,前面已经说到,a 是一个常量。。
再看一个易错的点:
char **s = "hello world";
这样是错误的,
因为 s 的类型是 char ** 而 "hello world "的类型是 char *
虽然都是地址, 但是指向的类型不一样,因此,不能这样用。,从其本质来分析,"hello world",代表一个地址,比如0x003001,这个地址中的内容是 'h'
,为 char 型,而 s 也保存一个地址 ,这个地址中的内容(*s) 是char * ,是一个指针类型, 所以两者类型是不一样的。 。。
如果是这样呢?
char **s;*s = "hello world";
貌似是合理的,编译也没有问题,但是 printf("%s",*s),就会崩溃
why??
咱来慢慢推敲一下。。
printf("%s",*s); 时,首先得有s 保存的地址,再在这个地址中找到 char * 的地址,即*s;
举例:
s = 0x1000;
在0x1000所在的内存单元中保存了"hello world"的地址 0x003001 , *s = 0x003001;
这样printf("%s",*s);
这样会先找到 0x1000,然后找到0x003001;
如果直接 char **s;
*s = "hello world";
s 变量中保存的是一个无效随机不可用的地址,即“hello world”这个字符串本身的地址还没有定义,谁也不知道它指向哪里。。。。,*s 指向不明确。。
所以用 char **s 时,要给它分配一个内存地址。
char **s ;
s = (char **) malloc(sizeof(char**));
*s = "hello world";
这样 s 给分配了了一个可用的地址,比如 s = 0x412f;
然后在 0x412f所在的内存中的位置,保存 "hello world"的值。。
再如:
#include <stdio.h>
void buf( char **s)
{
*s = "message";
}
int main()
{
char *s ;
buf(&s);
printf("%s\n",s);
}
二级指针的简单用法。。。。,说白了,二级指针保存的是一级指针的地址,它的类型是指针变量,而一级指针保存的是指向数据所在的内存单元的地址,虽然都是地址,但是类型是不一样的。。。
先分析其执行语句
./darknet detect cfg/yolov3.cfg yolov3.weights data/dog.jpg
./darknet表示运行可执行文件darknet,接着输入其main函数中参数,具体见main函数
int main(int argc, char **argv)
{
//test_resize("data/bad.jpg");
//test_box();
//test_convolutional_layer();
if(argc < 2){
fprintf(stderr, "usage: %s <function>\n", argv[0]);
return 0;
}
gpu_index = find_int_arg(argc, argv, "-i", 0);
if(find_arg(argc, argv, "-nogpu")) {
gpu_index = -1;
}
#ifndef GPU
gpu_index = -1;
#else
if(gpu_index >= 0){
cuda_set_device(gpu_index);
}
#endif
//strcmp函数 设这两个字符串为str1,str2,若str1==str2,则返回零;若str1<str2,则返回负数;若str1>str2,则返回正数。
if (0 == strcmp(argv[1], "average")){
average(argc, argv);
} else if (0 == strcmp(argv[1], "yolo")){
run_yolo(argc, argv);
} else if (0 == strcmp(argv[1], "super")){
run_super(argc, argv);
} else if (0 == strcmp(argv[1], "lsd")){
run_lsd(argc, argv);
} else if (0 == strcmp(argv[1], "detector")){
run_detector(argc, argv);
} else if (0 == strcmp(argv[1], "detect")){
float thresh = find_float_arg(argc, argv, "-thresh", .5);
char *filename = (argc > 4) ? argv[4]: 0;
char *outfile = find_char_arg(argc, argv, "-out", 0);
int fullscreen = find_arg(argc, argv, "-fullscreen");
test_detector("cfg/coco.data", argv[2], argv[3], filename, thresh, .5, outfile, fullscreen);
} else if (0 == strcmp(argv[1], "cifar")){
run_cifar(argc, argv);
} else if (0 == strcmp(argv[1], "go")){
run_go(argc, argv);
} else if (0 == strcmp(argv[1], "rnn")){
run_char_rnn(argc, argv);
} else if (0 == strcmp(argv[1], "coco")){
run_coco(argc, argv);
} else if (0 == strcmp(argv[1], "classify")){
predict_classifier("cfg/imagenet1k.data", argv[2], argv[3], argv[4], 5);
} else if (0 == strcmp(argv[1], "classifier")){
run_classifier(argc, argv);
} else if (0 == strcmp(argv[1], "regressor")){
run_regressor(argc, argv);
} else if (0 == strcmp(argv[1], "isegmenter")){
run_isegmenter(argc, argv);
} else if (0 == strcmp(argv[1], "segmenter")){
run_segmenter(argc, argv);
} else if (0 == strcmp(argv[1], "art")){
run_art(argc, argv);
} else if (0 == strcmp(argv[1], "tag")){
run_tag(argc, argv);
} else if (0 == strcmp(argv[1], "3d")){
composite_3d(argv[2], argv[3], argv[4], (argc > 5) ? atof(argv[5]) : 0);
} else if (0 == strcmp(argv[1], "test")){
test_resize(argv[2]);
} else if (0 == strcmp(argv[1], "nightmare")){
run_nightmare(argc, argv);
} else if (0 == strcmp(argv[1], "rgbgr")){
rgbgr_net(argv[2], argv[3], argv[4]);
} else if (0 == strcmp(argv[1], "reset")){
reset_normalize_net(argv[2], argv[3], argv[4]);
} else if (0 == strcmp(argv[1], "denormalize")){
denormalize_net(argv[2], argv[3], argv[4]);
} else if (0 == strcmp(argv[1], "statistics")){
statistics_net(argv[2], argv[3]);
} else if (0 == strcmp(argv[1], "normalize")){
normalize_net(argv[2], argv[3], argv[4]);
} else if (0 == strcmp(argv[1], "rescale")){
rescale_net(argv[2], argv[3], argv[4]);
} else if (0 == strcmp(argv[1], "ops")){
operations(argv[2]);
} else if (0 == strcmp(argv[1], "speed")){
speed(argv[2], (argc > 3 && argv[3]) ? atoi(argv[3]) : 0);
} else if (0 == strcmp(argv[1], "oneoff")){
oneoff(argv[2], argv[3], argv[4]);
} else if (0 == strcmp(argv[1], "oneoff2")){
oneoff2(argv[2], argv[3], argv[4], atoi(argv[5]));
} else if (0 == strcmp(argv[1], "print")){
print_weights(argv[2], argv[3], atoi(argv[4]));
} else if (0 == strcmp(argv[1], "partial")){
partial(argv[2], argv[3], argv[4], atoi(argv[5]));
} else if (0 == strcmp(argv[1], "average")){
average(argc, argv);
} else if (0 == strcmp(argv[1], "visualize")){
visualize(argv[2], (argc > 3) ? argv[3] : 0);
} else if (0 == strcmp(argv[1], "mkimg")){
mkimg(argv[2], argv[3], atoi(argv[4]), atoi(argv[5]), atoi(argv[6]), argv[7]);
} else if (0 == strcmp(argv[1], "imtest")){
test_resize(argv[2]);
} else {
fprintf(stderr, "Not an option: %s\n", argv[1]);
}
return 0;
}
通过else if 和strcmp函数比较输入命令,选择对应的run_***函数,官网给的测试命令是detect
else if (0 == strcmp(argv[1], "detect")){
float thresh = find_float_arg(argc, argv, "-thresh", .5);
char *filename = (argc > 4) ? argv[4]: 0;
char *outfile = find_char_arg(argc, argv, "-out", 0);
int fullscreen = find_arg(argc, argv, "-fullscreen");
test_detector("cfg/coco.data", argv[2], argv[3], filename, thresh, .5, outfile, fullscreen);
./darknet detect cfg/yolov3.cfg yolov3.weights data/dog.jpg
cfg/yolov3.cfg为测试配置文件,
要注意的是,测试的时候和训练网络的时候配置文件开头的batch、subdivisions要修改(表示一次读入数据量,测试为1即可)
./darknet detect cfg/yolov3.cfg yolov3.weights data/dog.jpg
yolov3.weights为权重文件,当前目录下
data\dog.jpg为测试文件。
继续回到main函数中,查看run
总结:根据参数选择执行函数,加载数据,配置,权重
参考: