C++ 的 C 接口Hashmap 库无法正常工作
我对C的新手相对较新,尽管我已经使用其他语言开发了很长时间。试图在Coursera课程中进行C& C ++我决定通过为现有项目编写包装纸来挑战自己,这将转化为我最终将它们用于我的现实世界应用中。
我正在构建一个C接口,用于 Google Sparse Hash Map Map Map Map Map Map Map Map Map Map ,使用C接口/包装的指南(在这里),但似乎有任何数据未插入的问题,或者一旦插入就无法读取数据?
这就是我所拥有的。
C ++对象
SparseHashmap.cpp
#include "sparsehashmap.h"
#include<string>
SparseHashMap::SparseHashMap(){_shash.set_deleted_key("");}
void SparseHashMap::insert(const char* arg1, const char* arg2)
{
_shash[arg1] = arg2;
}
const char* SparseHashMap::read(const char* key)
{
return _shash[key];
}
int SparseHashMap::exists(const char* key)
{
if (_shash.find(key) == _shash.end())
{
return false;
}
else
{
return true;
}
}
void SparseHashMap::remove(const char* key)
{
_shash.erase(key);
}
int SparseHashMap::length()
{
return (int) _shash.size();
}
void SparseHashMap::flush()
{
_shash.clear();
}
SparseHashmap.h
#ifndef __CPPSPARSEHASH__
#define __CPPSPARSEHASH__
#include <iostream>
#include <sparsehash/sparse_hash_map> //https://github.com/sparsehash/sparsehash
typedef google::sparse_hash_map<const char*, const char*> _SPARSEHASH;
class SparseHashMap
{
private:
_SPARSEHASH _shash;
public:
SparseHashMap();
void insert(const char* arg1, const char* arg2);
const char* read(const char* key);
int exists(const char* key);
void remove(const char* key);
int length();
void flush();
};
#endif // __CPPSPARSEHASH__
c Wrapper
sparse.h
#ifndef __FOSPARSE_H__
#define __FOSPARSE_H__
#ifdef __cplusplus
extern "C" {
#endif
struct CSparseHashMap;
typedef struct CSparseHashMap _SparseHashMap;
_SparseHashMap *sparsehashmap_create();
void sparsehashmap_destroy(_SparseHashMap *shm);
void sparsehashmap_insert (_SparseHashMap *shm, const char* arg1, const char* arg2);
const char* sparsehashmap_read (_SparseHashMap *shm, const char* key);
int sparsehashmap_exists (_SparseHashMap *shm, const char* key);
void sparsehashmap_remove (_SparseHashMap *shm, const char* key);
int sparsehashmap_length (_SparseHashMap *shm);
void sparsehashmap_flush (_SparseHashMap *shm);
#ifdef __cplusplus
}
#endif
#endif
sparse.cpp
#include <stdlib.h>
#include "sparse.h"
#include "sparsehashmap.h"
struct CSparseHashMap {
void *obj;
};
_SparseHashMap *sparsehashmap_create()
{
_SparseHashMap *shm;
SparseHashMap *obj;
shm = (__typeof__(shm))malloc(sizeof(*shm));
obj = new SparseHashMap();
shm->obj = obj;
return shm;
}
void sparsehashmap_destroy(_SparseHashMap *shm)
{
if (shm == NULL)
return;
delete static_cast<SparseHashMap *>(shm->obj);
free(shm);
}
void sparsehashmap_insert(_SparseHashMap *shm, const char* arg1, const char* arg2)
{
SparseHashMap *obj;
if (shm == NULL)
return;
obj = static_cast<SparseHashMap *>(shm->obj);
obj->insert(arg1, arg2);
}
const char* sparsehashmap_read(_SparseHashMap *shm, const char* key)
{
SparseHashMap *obj;
if (shm == NULL)
return 0;
obj = static_cast<SparseHashMap *>(shm->obj);
return obj->read(key);
}
int sparsehashmap_exists(_SparseHashMap *shm, const char* key)
{
SparseHashMap *obj;
if (shm == NULL)
return 0;
obj = static_cast<SparseHashMap *>(shm->obj);
return obj->exists(key);
}
void sparsehashmap_remove(_SparseHashMap *shm, const char* key)
{
SparseHashMap *obj;
if (shm == NULL)
return;
obj = static_cast<SparseHashMap *>(shm->obj);
obj->remove(key);
}
int sparsehashmap_length(_SparseHashMap *shm)
{
SparseHashMap *obj;
if (shm == NULL)
return 0;
obj = static_cast<SparseHashMap *>(shm->obj);
return obj->length();
}
void sparsehashmap_flush(_SparseHashMap *shm)
{
SparseHashMap *obj;
if (shm == NULL)
return;
obj = static_cast<SparseHashMap *>(shm->obj);
obj->flush();
}
test
> main.c
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include "sparse.h"
#define MAXCHAR 256
int main(int argc, char* argv[])
{
// Create Pointer to Sparsehashmap object
_SparseHashMap *fshm = sparsehashmap_create();
/*
Open File specified in command line argument <argv[1]>
and initialise array pointer to hold the line data
*/
FILE *fp;
char row[MAXCHAR];
int ct = 0;
fp = fopen(argv[1], "r");
/*
Loop through the file, split the row using a single space
as a delimeter, and insert as <key> => <value> into the
sparsehashmap
*/
while (feof(fp) != true)
{
char key[MAXCHAR], value[MAXCHAR];
fgets(row, MAXCHAR, fp);
sscanf(row, "%s %s", key, value);
// if( (ct % 100) == 0 )
// printf("Key: %s\tValue: %s\n", key, value);
sparsehashmap_insert(fshm, key, value);
ct++;
}
// close the file as it is no longer needed.
fclose(fp);
// Print the total number of times the while loop ran
printf("%d Total entries.\n", ct);
// Print the length of the Sparsehashmap
printf("C SparseHashMap: Length of Hashmap = %d\n", sparsehashmap_length(fshm));
/*
Read, Exists and Remove Examples
*/
printf("C SparseHashMap: _SparseHashMap[\"63-5039337\"] = %s\n", sparsehashmap_read(fshm, "63-5039337"));
printf("C SparseHashMap: _SparseHashMap[\"26-8663826\"] = %s\n", sparsehashmap_read(fshm, "26-8663826"));
printf("C SparseHashMap: _SparseHashMap[\"87-9801138\"] = %s\n", sparsehashmap_read(fshm, "87-9801138"));
printf("C SparseHashMap: Key Exists [\"15-8895492\"] = %d\n", sparsehashmap_exists(fshm, "15-8895492"));
printf("C SparseHashMap: Key Exists [\"22-4942175\"] = %d\n", sparsehashmap_exists(fshm, "22-4942175"));
printf("C SparseHashMap: Remove Key From Hashmap...\n");
printf("C SparseHashMap: Remove Key From Hashmap [\"63-5039337\"]\n");
sparsehashmap_remove(fshm, "63-5039337");
printf("C SparseHashMap: Remove Key From Hashmap [\"20-6892893\"]\n");
sparsehashmap_remove(fshm, "20-6892893");
printf("C SparseHashMap: Remove Key From Hashmap [\"58-8150180\"]\n");
sparsehashmap_remove(fshm, "58-8150180");
printf("C SparseHashMap: Length of Hashmap = %d\n", sparsehashmap_length(fshm));
/*
Destroy the Sparsehashmap to free its
memory allocation.
*/
printf("C SparseHashMap: Destroy Hashmap\n");
sparsehashmap_destroy(fshm);
printf("C SparseHashMap: Freed");
return 0;
}
我已经创建了我正在插入和查询的数据的角度,可以找到在这里。
一旦构建,我将其运行在模拟数据的文件上,但是在2000个测试条目的文件中,这些是我获得的结果,我获得了
2001 Total entries. /* times file is looped with fgets() */
C SparseHashMap: Length of Hashmap = 1 /* Size of the hashmap */
C SparseHashMap: _SparseHashMap["63-5039337"] = (null) /* Read Function Response */
C SparseHashMap: _SparseHashMap["26-8663826"] = (null) /* Read Function Response */
C SparseHashMap: _SparseHashMap["87-9801138"] = (null) /* Read Function Response */
C SparseHashMap: Key Exists ["15-8895492"] = 0
C SparseHashMap: Key Exists ["22-4942175"] = 0
C SparseHashMap: Remove Key From Hashmap ["63-5039337"]
C SparseHashMap: Remove Key From Hashmap ["20-6892893"]
C SparseHashMap: Remove Key From Hashmap ["58-8150180"]
C SparseHashMap: Length of Hashmap = 3 /* Size of the hashmap */
C SparseHashMap: Destroy Hashmap
C SparseHashMap: Freed%
Hash Map的大小以一个(显然是在插入2000个条目之后),它无法阅读输入数据的任何键,然后在执行多个删除后,长度跳到三个?
我了解我正在使用的指南比使用哈希地图要基础,但是想知道是否有人可以将我指向我对此有问题的位置?以及我应该如何将其修改以使操作按预期运行?
任何指导都将不胜感激。
======== edit ========== =
该问题似乎是将指针映射到指针上。修改*。cpp
要获取/返回/返回std :: string
的文件,并在从C指令传递之前执行相关的转换
./run MOCK_DATA.txt
2001 Total entries.
C SparseHashMap: Length of Hashmap = 2000
C SparseHashMap: _SparseHashMap["63-5039337"] = {"id":1,"first_name":"Ilario","last_name":"Thickins","email":"[email protected]","gender":"Male","ip_address":"54.113.8.103"}
C SparseHashMap: _SparseHashMap["26-8663826"] = {"id":35,"first_name":"Mignonne","last_name":"Oakden","email":"[email protected]","gender":"Female","ip_address":"41.14.68.148"}
C SparseHashMap: _SparseHashMap["87-9801138"] = {"id":1989,"first_name":"Mavis","last_name":"Collingwood","email":"[email protected]","gender":"Female","ip_address":"56.70.97.65"}
C SparseHashMap: Key Exists ["15-8895492"] = 1
C SparseHashMap: Key Exists ["22-4942175"] = 1
C SparseHashMap: Remove Key From Hashmap ["63-5039337"]
C SparseHashMap: Remove Key From Hashmap ["20-6892893"]
C SparseHashMap: Remove Key From Hashmap ["58-8150180"]
C SparseHashMap: Length of Hashmap = 1997
C SparseHashMap: Destroy Hashmap
C SparseHashMap: Freed
I am relatively new to C, although I have been developing with other languages for an extended period of time. In an attempt to "Learn by doing", whilst working through a coursera course on C & C++ I decided to challenge myself with both by writing a wrapper for an existing project, which would translate to what I would eventually be using them for in my real world application of them.
I am building a C interface for a C++ implementation of Google Sparse Hash Map, using a guide on C interfaces / wrapping (here), but seem to be having issues with either data not inserting, or not being able to read the data once inserted?
This is what I have.
The C++ Object
sparsehashmap.cpp
#include "sparsehashmap.h"
#include<string>
SparseHashMap::SparseHashMap(){_shash.set_deleted_key("");}
void SparseHashMap::insert(const char* arg1, const char* arg2)
{
_shash[arg1] = arg2;
}
const char* SparseHashMap::read(const char* key)
{
return _shash[key];
}
int SparseHashMap::exists(const char* key)
{
if (_shash.find(key) == _shash.end())
{
return false;
}
else
{
return true;
}
}
void SparseHashMap::remove(const char* key)
{
_shash.erase(key);
}
int SparseHashMap::length()
{
return (int) _shash.size();
}
void SparseHashMap::flush()
{
_shash.clear();
}
sparsehashmap.h
#ifndef __CPPSPARSEHASH__
#define __CPPSPARSEHASH__
#include <iostream>
#include <sparsehash/sparse_hash_map> //https://github.com/sparsehash/sparsehash
typedef google::sparse_hash_map<const char*, const char*> _SPARSEHASH;
class SparseHashMap
{
private:
_SPARSEHASH _shash;
public:
SparseHashMap();
void insert(const char* arg1, const char* arg2);
const char* read(const char* key);
int exists(const char* key);
void remove(const char* key);
int length();
void flush();
};
#endif // __CPPSPARSEHASH__
The C Wrapper
sparse.h
#ifndef __FOSPARSE_H__
#define __FOSPARSE_H__
#ifdef __cplusplus
extern "C" {
#endif
struct CSparseHashMap;
typedef struct CSparseHashMap _SparseHashMap;
_SparseHashMap *sparsehashmap_create();
void sparsehashmap_destroy(_SparseHashMap *shm);
void sparsehashmap_insert (_SparseHashMap *shm, const char* arg1, const char* arg2);
const char* sparsehashmap_read (_SparseHashMap *shm, const char* key);
int sparsehashmap_exists (_SparseHashMap *shm, const char* key);
void sparsehashmap_remove (_SparseHashMap *shm, const char* key);
int sparsehashmap_length (_SparseHashMap *shm);
void sparsehashmap_flush (_SparseHashMap *shm);
#ifdef __cplusplus
}
#endif
#endif
sparse.cpp
#include <stdlib.h>
#include "sparse.h"
#include "sparsehashmap.h"
struct CSparseHashMap {
void *obj;
};
_SparseHashMap *sparsehashmap_create()
{
_SparseHashMap *shm;
SparseHashMap *obj;
shm = (__typeof__(shm))malloc(sizeof(*shm));
obj = new SparseHashMap();
shm->obj = obj;
return shm;
}
void sparsehashmap_destroy(_SparseHashMap *shm)
{
if (shm == NULL)
return;
delete static_cast<SparseHashMap *>(shm->obj);
free(shm);
}
void sparsehashmap_insert(_SparseHashMap *shm, const char* arg1, const char* arg2)
{
SparseHashMap *obj;
if (shm == NULL)
return;
obj = static_cast<SparseHashMap *>(shm->obj);
obj->insert(arg1, arg2);
}
const char* sparsehashmap_read(_SparseHashMap *shm, const char* key)
{
SparseHashMap *obj;
if (shm == NULL)
return 0;
obj = static_cast<SparseHashMap *>(shm->obj);
return obj->read(key);
}
int sparsehashmap_exists(_SparseHashMap *shm, const char* key)
{
SparseHashMap *obj;
if (shm == NULL)
return 0;
obj = static_cast<SparseHashMap *>(shm->obj);
return obj->exists(key);
}
void sparsehashmap_remove(_SparseHashMap *shm, const char* key)
{
SparseHashMap *obj;
if (shm == NULL)
return;
obj = static_cast<SparseHashMap *>(shm->obj);
obj->remove(key);
}
int sparsehashmap_length(_SparseHashMap *shm)
{
SparseHashMap *obj;
if (shm == NULL)
return 0;
obj = static_cast<SparseHashMap *>(shm->obj);
return obj->length();
}
void sparsehashmap_flush(_SparseHashMap *shm)
{
SparseHashMap *obj;
if (shm == NULL)
return;
obj = static_cast<SparseHashMap *>(shm->obj);
obj->flush();
}
The Test
main.c
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include "sparse.h"
#define MAXCHAR 256
int main(int argc, char* argv[])
{
// Create Pointer to Sparsehashmap object
_SparseHashMap *fshm = sparsehashmap_create();
/*
Open File specified in command line argument <argv[1]>
and initialise array pointer to hold the line data
*/
FILE *fp;
char row[MAXCHAR];
int ct = 0;
fp = fopen(argv[1], "r");
/*
Loop through the file, split the row using a single space
as a delimeter, and insert as <key> => <value> into the
sparsehashmap
*/
while (feof(fp) != true)
{
char key[MAXCHAR], value[MAXCHAR];
fgets(row, MAXCHAR, fp);
sscanf(row, "%s %s", key, value);
// if( (ct % 100) == 0 )
// printf("Key: %s\tValue: %s\n", key, value);
sparsehashmap_insert(fshm, key, value);
ct++;
}
// close the file as it is no longer needed.
fclose(fp);
// Print the total number of times the while loop ran
printf("%d Total entries.\n", ct);
// Print the length of the Sparsehashmap
printf("C SparseHashMap: Length of Hashmap = %d\n", sparsehashmap_length(fshm));
/*
Read, Exists and Remove Examples
*/
printf("C SparseHashMap: _SparseHashMap[\"63-5039337\"] = %s\n", sparsehashmap_read(fshm, "63-5039337"));
printf("C SparseHashMap: _SparseHashMap[\"26-8663826\"] = %s\n", sparsehashmap_read(fshm, "26-8663826"));
printf("C SparseHashMap: _SparseHashMap[\"87-9801138\"] = %s\n", sparsehashmap_read(fshm, "87-9801138"));
printf("C SparseHashMap: Key Exists [\"15-8895492\"] = %d\n", sparsehashmap_exists(fshm, "15-8895492"));
printf("C SparseHashMap: Key Exists [\"22-4942175\"] = %d\n", sparsehashmap_exists(fshm, "22-4942175"));
printf("C SparseHashMap: Remove Key From Hashmap...\n");
printf("C SparseHashMap: Remove Key From Hashmap [\"63-5039337\"]\n");
sparsehashmap_remove(fshm, "63-5039337");
printf("C SparseHashMap: Remove Key From Hashmap [\"20-6892893\"]\n");
sparsehashmap_remove(fshm, "20-6892893");
printf("C SparseHashMap: Remove Key From Hashmap [\"58-8150180\"]\n");
sparsehashmap_remove(fshm, "58-8150180");
printf("C SparseHashMap: Length of Hashmap = %d\n", sparsehashmap_length(fshm));
/*
Destroy the Sparsehashmap to free its
memory allocation.
*/
printf("C SparseHashMap: Destroy Hashmap\n");
sparsehashmap_destroy(fshm);
printf("C SparseHashMap: Freed");
return 0;
}
I have created a gist of the data that I am inserting and querying, which can be found here.
Once built, I run it against the file of mock data, but of the file of 2000 test entries, these are the results I get
2001 Total entries. /* times file is looped with fgets() */
C SparseHashMap: Length of Hashmap = 1 /* Size of the hashmap */
C SparseHashMap: _SparseHashMap["63-5039337"] = (null) /* Read Function Response */
C SparseHashMap: _SparseHashMap["26-8663826"] = (null) /* Read Function Response */
C SparseHashMap: _SparseHashMap["87-9801138"] = (null) /* Read Function Response */
C SparseHashMap: Key Exists ["15-8895492"] = 0
C SparseHashMap: Key Exists ["22-4942175"] = 0
C SparseHashMap: Remove Key From Hashmap ["63-5039337"]
C SparseHashMap: Remove Key From Hashmap ["20-6892893"]
C SparseHashMap: Remove Key From Hashmap ["58-8150180"]
C SparseHashMap: Length of Hashmap = 3 /* Size of the hashmap */
C SparseHashMap: Destroy Hashmap
C SparseHashMap: Freed%
The size of the Hash Map starts at one (after apparently inserting 2000 entries), it is unable to read any keys from the input data, and then after it performs a number of removals, the length jumps to three?
I understand that the guide I am working from is a bit more basic than working with a hash map, but was wondering if anyone could point me to where I am going wrong with this? and how I should be looking at modifying it to have the operations working as expected?
Any guidance would be greatly appreciated.
======== EDIT ========
The issue seemed to be mapping pointers to pointers. After amending the *.cpp
files to take / return std::string
, and performing the relevant conversions before passing from the C instructions the interface began working as intended
./run MOCK_DATA.txt
2001 Total entries.
C SparseHashMap: Length of Hashmap = 2000
C SparseHashMap: _SparseHashMap["63-5039337"] = {"id":1,"first_name":"Ilario","last_name":"Thickins","email":"[email protected]","gender":"Male","ip_address":"54.113.8.103"}
C SparseHashMap: _SparseHashMap["26-8663826"] = {"id":35,"first_name":"Mignonne","last_name":"Oakden","email":"[email protected]","gender":"Female","ip_address":"41.14.68.148"}
C SparseHashMap: _SparseHashMap["87-9801138"] = {"id":1989,"first_name":"Mavis","last_name":"Collingwood","email":"[email protected]","gender":"Female","ip_address":"56.70.97.65"}
C SparseHashMap: Key Exists ["15-8895492"] = 1
C SparseHashMap: Key Exists ["22-4942175"] = 1
C SparseHashMap: Remove Key From Hashmap ["63-5039337"]
C SparseHashMap: Remove Key From Hashmap ["20-6892893"]
C SparseHashMap: Remove Key From Hashmap ["58-8150180"]
C SparseHashMap: Length of Hashmap = 1997
C SparseHashMap: Destroy Hashmap
C SparseHashMap: Freed
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您正在将指针映射到指针,但您可能打算将字符串映射到字符串。
使用
std::map
可能是:这仅意味着您正在将指针映射到指针。
你所有的指针都来自这两个对象。
每次向哈希映射添加键时,您使用的键都是指向本地
key
数组的指针(在循环的每次迭代中始终相同)。该值是指向本地value
数组的指针(同样,在循环的每次迭代中它始终相同)。这就是为什么您的地图中只有 1 个条目。您已成功将&key[0]
映射到&value[0]
。您可能想要的是使用
std::string
。或者
然后你有更大的鱼要炸
现在你必须担心你的
read
实现只返回一个指针,而不是返回一个字符串。您刚刚继承了 C 中管理字符串的所有问题。您可以像std::string::c_str
一样对待它,其中您返回哈希条目的c_str
,但这将是如果您向映射添加另一个条目或删除一个条目,则该条目将无效,因此必须清楚地记录您的语义,否则您必须为返回的字符串的副本分配一个缓冲区,并允许再次释放该缓冲区,就像这样在C.(我很高兴C++ 是一回事。)You are mapping pointers to pointers, but you likely intended to map strings to strings.
With a
std::map
that might be:That just means that you are mapping pointers to pointers.
All of your pointers come from these two objects.
Every time you add a key to your hash map, you are using a key which is a pointer to your local
key
array (which is always the same on every iteration of the loop). And the value is a pointer to your localvalue
array (again, which is always the same on every iteration of the loop). That's why you have only 1 entry in your map. You have successfully mapped&key[0]
to&value[0]
.What you probably want is to use
std::string
.Or
Then you have bigger fish to fry
Now you have to worry about the fact that your implementation of
read
just returns a pointer, rather than returning a string. You just inherited all the problems of managing strings in C. You could treat it likestd::string::c_str
where you return the hash entry'sc_str
, but this will be invalidated if you add another entry to the map or remove one, so your semantics will have to be clearly documented, or else you'll have to allocate a buffer for a copy of your returned string and permit freeing that buffer again as is the way in C. (I'm glad C++ is a thing.)