Using intersect in R with Rcpp [closed] - rcpp

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 6 years ago.
Improve this question
I am new to Rcpp and am trying to write a simple function that would take a list of character vectors (myList), and a separate character vector (vec1), and would return a list of intersections between each list vector and vec1.
I can do this in R easily enough:
myList <- list(
c('apple','banana','orange','pineapple'),
c('pear','pineapple','watermelon'),
c('orange','apple','pineapple'),
NA,
c('watermelon','lime','apple','banana'))
vec1 <- c('apple','pineapple','banana')
# R implementation
lapply(myList, function(x) intersect(x, vec1))
But I am confused as to how to implement this with Rcpp. Here is my attempt:
cppFunction('
List intersectList (List input, StringVector vec) {
int n = input.size();
List out(n);
for (int i = 0; i < n; i++) {
StringVector sp = Rcpp::as< std::vector<std::string> > (input[i]);
if (sp.length() > 0) {
out[i] = intersect(sp, vec);
}
}
return out;
}
')
...however this results in an error:
Error in sourceCpp(code = code, env = env, rebuild = rebuild, cacheDir = cacheDir, :
Error 1 occurred building shared library.
file1510d6dbd767c.cpp:14:17: error: no viable conversion from 'std::__1::vector<std::__1::basic_string<char>, std::__1::allocator<std::__1::basic_string<char> > >' to 'StringVector' (aka 'Vector<16>')
StringVector sp = Rcpp::as< std::vector<std::string> > (input[i]);
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Library/Frameworks/R.framework/Versions/3.3/Resources/library/Rcpp/include/Rcpp/vector/Vector.h:65:5: note: candidate constructor not viable: no known conversion from 'std::__1::vector<std::__1::basic_string<char>, std::__1::allocator<std::__1::basic_string<char> > >' to 'const Rcpp::Vector<16, PreserveStorage> &' for 1st argument
Vector( const Vector& other){
^
/Library/Frameworks/R.framework/Versions/3.3/Resources/library/Rcpp/include/Rcpp/vector/Vector.h:73:5: note: candidate constructor not viable: no known conversion from 'std::__1::vector<std::__1::basic_string<char>, std::__1::allocator<std::__1::basic_string<char> > >' to 'SEXP' (aka 'SEXPREC *') for 1st argument
Vector( SEXP x ) {
^
/Library/Frameworks/R.framework/Versions/3.3/Resources/library/Rcpp/include/Rcpp/vector/Vector.h:101:5: note: candidate constructor not viable: no known conversion from 'std::__1::vector<std::__1::basic_string<char>, std::__1::allocator<std::__1::basic_string<char> > >' to 'const std::string &' (aka 'const basic_string<char, char_traits<char>, allocator<char> > &') for 1st argument
Vector( const std::string& st ){
^
/Library/Frameworks/R.framework/Versions/3.3/Resources/library/Rcpp/include/Rcpp/vector/Vector.h:107:5: note: candidate constructor not viable: no known conversion from 'std::__1::vector<std::__1::basic_string<char>, std::__1::allocator<std::__1::basic_string<char> > >' to 'const char *' for 1st argument
Vector( const char* st ) {
^
/Library/Frameworks/R.framework/Versions/3.3/Resources/library/Rcpp/include/Rcpp/vector/Vector.h:128:5: note: candidate constructor not viable: no known conversion from 'std::__1::vector<std::__1::basic_string<char>, std::__1::allocator<std::__1::basic_string<char> > >' to 'const int &' for 1st argument
Vector( const int& size ) {
^
/Library/Frameworks/R.framework/Versions/3.3/Resources/library/Rcpp/include/Rcpp/vector/Vector.h:133:5: note: candidate constructor not viable: no known conversion from 'std::__1::vector<std::__1::basic_string<char>, std::__1::allocator<std::__1::basic_string<char> > >' to 'const Rcpp::Dimension &' for 1st argument
Vector( const Dimension& dims) {
^
/Library/Frameworks/R.framework/Versions/3.3/Resources/library/Rcpp/include/Rcpp/vector/Vector.h:78:5: note: candidate template ignored: could not match 'GenericProxy' against 'vector'
Vector( const GenericProxy<Proxy>& proxy ){
^
/Library/Frameworks/R.framework/Versions/3.3/Resources/library/Rcpp/include/Rcpp/vector/Vector.h:123:42: note: candidate template ignored: disabled by 'enable_if' [with T = std::__1::vector<std::__1::basic_string<char>, std::__1::allocator<std::__1::basic_string<char> > >]
typename Rcpp::traits::enable_if<traits::is_arithmetic<T>::value, void>::type* = 0) {
^
/Library/Frameworks/R.framework/Versions/3.3/Resources/library/Rcpp/include/Rcpp/vector/Vector.h:146:45: note: candidate template ignored: disabled by 'enable_if' [with T = std::__1::vector<std::__1::basic_string<char>, std::__1::allocator<std::__1::basic_string<char> > >]
typename Rcpp::traits::enable_if<traits::is_bool<T>::value && RTYPE == LGLSXP, void>::type* = 0) {
^
/Library/Frameworks/R.framework/Versions/3.3/Resources/library/Rcpp/include/Rcpp/vector/Vector.h:162:5: note: candidate template ignored: could not match 'VectorBase' against 'vector'
Vector( const VectorBase<RTYPE,NA,VEC>& other ) {
^
/Library/Frameworks/R.framework/Versions/3.3/Resources/library/Rcpp/include/Rcpp/vector/Vector.h:176:5: note: candidate template ignored: could not match 'SingleLogicalResult' against 'vector'
Vector( const sugar::SingleLogicalResult<NA,T>& obj ) {
^
1 error generated.
make: *** [file1510d6dbd767c.o] Error 1
In this particular case, the R implementation is simple and fast, so Rcpp may not be necessary. But I would like to understand the Rcpp implementation, as it would give me a better understanding of how to work with vectors and lists with Rcpp.

Briefly:
The function is called intersect; your title talks about intercept. Not the same thing.
The unit test for intersect() is a one-liner (see below). If I were you I'd start from it and try it with StringVector types.
You are jumping bacl and forth between StringVector and std::vector<std::string>. Why? If you change StringVector sp = Rcpp::as< std::vector<std::string> > (input[i]); to use StringVector in the as<>() you might be good. [ Untested, no time right now. ]
The test function (included in every version of Rcpp in file unitTests/cpp/sugar.cpp is:
// [[Rcpp::export]]
IntegerVector runit_intersect( IntegerVector x, IntegerVector y){
return intersect( x, y ) ;
}

Thanks to Dirk Eddelbuettel for suggesting the following:
> cppFunction('
+ List intersectList (List input, StringVector vec) {
+
+ int n = input.size();
+ List out(n);
+
+ for (int i = 0; i < n; i++) {
+
+ StringVector sp = Rcpp::as< StringVector > (input[i]);
+
+ if (sp.length() > 0) {
+ out[i] = intersect(sp, vec);
+ }
+ }
+
+ return out;
+
+ }
+ ')
>
> myList <- list(
+ c('apple','banana','orange','pineapple'),
+ c('pear','pineapple','watermelon'),
+ c('orange','apple','pineapple'),
+ NA,
+ c('watermelon','lime','apple','banana'))
>
> vec1 <- c('apple','pineapple','banana')
>
> intersectList(myList, vec1)
[[1]]
[1] "pineapple" "banana" "apple"
[[2]]
[1] "pineapple"
[[3]]
[1] "pineapple" "apple"
[[4]]
character(0)
[[5]]
[1] "banana" "apple"

Related

Conversion of Rcpp::NumericMatrix to Eigen::MatrixXd

I am facing a very similar issue to these questions:
convert Rcpp::NumericVector to Eigen::VectorXd
Converting between NumericVector/Matrix and VectorXd/MatrixXd in Rcpp(Eigen) to perform Cholesky solve
I am writing an R-package, that uses the RcppEigen library for Matrix arithmetic. My problem is that the project is not compiling because of an error in the conversion of the Rcpp::NumericMatrix input to an Eigen::MatrixXd.
The file looks like this:
#include <map>
#include <Rcpp.h>
...
using namespace Eigen;
...
// [[Rcpp::export]]
Rcpp::List my_function(Rcpp::NumericMatrix input_matrix)
{
...
Map<MatrixXd> GATE_matrixx(Rcpp::as<Map<MatrixXd> >(GATE_matrix));
...
}
This gives me the following error:
Myfile.cpp:40:65: required from here
C:/Users/User/AppData/Local/Programs/R/R-4.2.2/library/Rcpp/include/Rcpp/internal/Exporter.h:31:31:error:
matching function for call to 'Eigen::Map<Eigen::Matrix<double, -1,
-1> >::Map(SEXPREC*&) 31 | Exporter( SEXP x ) : t(x) | ^ In file included from
C:/Users/User/AppData/Local/Programs/R/R-4.2.2/library/RcppEigen/include/Eigen/Core:19
from
C:/Users/User/AppData/Local/Programs/R/R-4.2.2/library/RcppEigen/include/Eigen/SparseCore:11
from
C:/Users/User/AppData/Local/Programs/R/R-4.2.2/library/RcppEigen/include/Eigen/Sparse:26
from Myfile.cpp:8
I have also tried to change the line to:
MatrixXd input_matrix_eigen(Rcpp::as\<MatrixXd\>(input_matrix));
This gives me the equivalent error :
Myfile.cpp:40:54: required from here
C:/Users/User/AppData/Local/Programs/R/R
4.2.2/library/RcppEigen/include/Eigen/src/Core/Matrix.h:332:31:error: matching function for call to 'Eigen::Matrix<double, -1,
-1>::_init1<SEXPREC*>(SEXPREC* const&)
Do you have any ideas?
If more information is required to evaluate the issue, just let me know.
If you use the command
RcppEigen::RcppEigen.package.skeleton("demoPackage")
an example package demoPackage is created for you which you can install the usual way. It contains example functions to create amd return a matrix:
// [[Rcpp::export]]
Eigen::MatrixXd rcppeigen_hello_world() {
Eigen::MatrixXd m1 = Eigen::MatrixXd::Identity(3, 3);
// Eigen::MatrixXd m2 = Eigen::MatrixXd::Random(3, 3);
// Do not use Random() here to not promote use of a non-R RNG
Eigen::MatrixXd m2 = Eigen::MatrixXd::Zero(3, 3);
for (auto i=0; i<m2.rows(); i++)
for (auto j=0; j<m2.cols(); j++)
m2(i,j) = R::rnorm(0, 1);
return m1 + 3 * (m1 + m2);
}
If you set the same seed as I do you should get the same matrix
> set.seed(42)
> demoPackage::rcppeigen_hello_world()
[,1] [,2] [,3]
[1,] 8.11288 -1.694095 1.089385
[2,] 1.89859 5.212805 -0.318374
[3,] 4.53457 -0.283977 10.055271
>

Caesar problem code generating "error: implicitly declaring library function 'strlen' with type 'unsigned long (const char *)'

I am doing the CS50 course and am on week 2. One of the problems of week 2 is called "Caesar". Essentially you have to write code which cyphers text by shifting letters that use the users inputted preferred number. After running my code I keep getting this error
"error: implicitly declaring library function 'strlen' with
type 'unsigned long (const char *)'
[-Werror,-Wimplicit-function-declaration]
for(i = 0, l = strlen(text); i < n; i++)"
This is the code:
int main(int argc, string argv[])
{
string n = argv[1];
int y = argc;
int key = get_int("./caesar ");//getting the number from the user
int k = (key);//assigning key a variable name.
string text = get_string("plaintext: ");//letting the user input their text.
if (key < 1)//Trying to make limit for acceptable input.
{
printf("ERROR");
return 1;
}
int l;
int i;
//for loop containing the encipher process
for(i = 0, l = strlen(text); i < n; i++)
{
if(isalpha(i))
{
if (isupper[i])
{
printf("ciphertext: %c",(text[i] + k)%26 + 65);
}
else (islower[i])
{
printf("ciphertext: %c",(text[i] + k)%26 + 65);
}
}
}
printf("ciphertext: %c", d || c);
return;
int checking_key(int y,string n)
int num = argc;
string key = y;
int num_key = atoi(key);
if(argc != 2)
{
return 0;
}
else
{
if (num_key > 0)
{
return num_key;
}
else
{
return 0;
}
}
}
From man strlen:
Synopsis
#include <string.h>
size_t strlen(const char *s);
Just like one needs to "include" cs50.h to use any of the get_* functions, string.h must be "include"d to access its functions, eg strlen.
Additionally (per comments):
The "ordered comparison" in the compile error
ordered comparison between pointer and integer ('int' and 'string' (aka 'char *')) [-Werror] for(i = 0, l = strlen(text); i < n; i++)
is i < n. Error says one of them is an int and one of them is a string.
On closer inspection this program is a long way from a clean compile. Recommend you follow along with the spec and "approach this problem one step at a time"

Can I dodge 'abstract class' in repeated 1-D integration using RcppNumerical

I am looking for a deterministic threadsafe Rcpp algorithm for 2-D numerical integration. RcppNumerical provides a partial interface to Cuba for multidimensional integration, but from my trials that appears not to be threadsafe in RcppParallel, and it probably uses a Monte Carlo method. That throws me back on repeated 1-dimensional integration. I have used this successfully with the (not threadsafe) R function Rdqags, but my (possibly naive) coding for RcppNumerical fails to compile because the nested class is abstract. Perhaps due to the operator() virtual function.
Can anyone suggest a way around this in RcppNumerical, or some alternative?
My test code emulating the 2-D example from https://github.com/yixuan/RcppNumerical is below. It gives errors like
cannot declare variable 'f2' to be of abstract type 'Normal2'
cannot declare variable 'f1' to be of abstract type 'Normal1'
Murray
// [[Rcpp::depends(RcppEigen)]]
// [[Rcpp::depends(RcppNumerical)]]
#include <RcppNumerical.h>
using namespace Numer;
// P(a1 < X1 < b1, a2 < X2 < b2), (X1, X2) ~ N([0], [1 rho])
// ([0], [rho 1])
class Normal2: public Func
{
private:
const double rho;
const double x;
double const1; // 2 * (1 - rho^2)
double const2; // 1 / (2 * PI) / sqrt(1 - rho^2)
public:
Normal2(const double& rho_, const double& x_) : rho(rho_), x(x_)
{
const1 = 2.0 * (1.0 - rho * rho);
const2 = 1.0 / (2 * M_PI) / std::sqrt(1.0 - rho * rho);
}
// PDF of bivariate normal
double operator()(const double& y)
{
double z = x * x - 2 * rho * x * y + y * y;
return const2 * std::exp(-z / const1);
}
};
class Normal1: public Func
{
private:
const double rho;
double a2, b2;
public:
Normal1(const double& rho_, const double& a2_, const double& b2_) : rho(rho_), a2(a2_), b2(b2_) {}
// integral in y dimension for given x
double operator()(const double& x)
{
Normal2 f2(rho, x);
double err_est;
int err_code;
const double res = integrate(f2, a2, b2, err_est, err_code);
return res;
}
};
// [[Rcpp::export]]
Rcpp::List integrate_test3()
{
double a1 = -1.0;
double b1 = 1.0;
double a2 = -1.0;
double b2 = 1.0;
Normal1 f1(0.5, a2, b2); // rho = 0.5
double err_est;
int err_code;
const double res = integrate(f1, a1, b1, err_est, err_code);
return Rcpp::List::create(
Rcpp::Named("approximate") = res,
Rcpp::Named("error_estimate") = err_est,
Rcpp::Named("error_code") = err_code
);
}
The Numer::Func class is an abstract class because of one undefined method:
virtual double operator()(const double& x) const = 0;
Now you are providing an implementation for
double operator()(const double& x)
which leaves the above method undefined and hence the class abstract. You should change this to
double operator()(const double& x) const
for both Normal1 and Normal2 to have your code compile.
BTW, my compiler (gcc 9.2) is even quite explicit about this problem:
59094915.cpp: In member function ‘double Normal1::operator()(const double&)’:
59094915.cpp:43:17: error: cannot declare variable ‘f2’ to be of abstract type ‘Normal2’
43 | Normal2 f2(rho, x);
| ^~
59094915.cpp:9:7: note: because the following virtual functions are pure within ‘Normal2’:
9 | class Normal2: public Func
| ^~~~~~~
In file included from /usr/local/lib/R/site-library/RcppNumerical/include/integration/wrapper.h:13,
from /usr/local/lib/R/site-library/RcppNumerical/include/RcppNumerical.h:16,
from 59094915.cpp:3:
/usr/local/lib/R/site-library/RcppNumerical/include/integration/../Func.h:26:20: note: ‘virtual double Numer::Func::operator()(const double&) const’
26 | virtual double operator()(const double& x) const = 0;
| ^~~~~~~~
59094915.cpp: In function ‘Rcpp::List integrate_test3()’:
59094915.cpp:58:13: error: cannot declare variable ‘f1’ to be of abstract type ‘Normal1’
58 | Normal1 f1(0.5, a2, b2); // rho = 0.5
| ^~
59094915.cpp:32:7: note: because the following virtual functions are pure within ‘Normal1’:
32 | class Normal1: public Func
| ^~~~~~~
In file included from /usr/local/lib/R/site-library/RcppNumerical/include/integration/wrapper.h:13,
from /usr/local/lib/R/site-library/RcppNumerical/include/RcppNumerical.h:16,
from 59094915.cpp:3:
/usr/local/lib/R/site-library/RcppNumerical/include/integration/../Func.h:26:20: note: ‘virtual double Numer::Func::operator()(const double&) const’
26 | virtual double operator()(const double& x) const = 0;
| ^~~~~~~~

Calling a Class member function in Global Scope using friend Gives 27 ERRORS

//My Header File
//Header File
#include<iostream>
using namespace std;
MyFloat rotate_right(MyFloat obj)
{
/*All that this function is supposed to do, is to return a new object, that object will
be having array elements in the order like 2.2 3.2 4.2 5.2 6.2 where the
original(object that is passed in parameter) object must be having array elements
in order like 3.2 4.2 5.2 6.2 2.2
*/
MyFloat c;
c.size = obj.size;
c.arr = nullptr;
c.arr = new float [obj.size];
c.arr[0] = obj.arr[obj.size - 1];
for(int i = 1,j=0; i < (obj.size - 1); i++,j++)
{
c.arr[j] = obj.arr[i];
}
return c;
}
class MyFloat
{
public:
MyFloat();//Default Constructor
MyFloat(int data);//Parameterized Constructor
MyFloat(MyFloat & const obj);//Copy Constructor
void input();//Filling Array
void PrintFloat();//For Displaying Array
MyFloat& operator=(MyFloat & const obj);//Assignment Operator Overloading
friend MyFloat rotate_right(MyFloat obj);/////////////This is the Function which is causing Problem/////////////
~MyFloat();//Destructor
private:
int size;//size of array
float *arr;
};
////////////This is the Cpp FILE Having Definition of All Functions
#include"My_Floats_Header.h"
MyFloat::MyFloat()
{
cout << "Default Constructor Called!" << endl;
size = 0;
arr = nullptr;
}
MyFloat::MyFloat(int _size)
{
cout << "Parametrized Constructor Called!" << endl;
size = _size;
arr = nullptr;
arr = new float [_size];
}
void MyFloat :: input()
{
for(int i = 0 ; i < size; i++)
{
cout << "Enter an Element = ";
cin >> arr[i];
}
}
MyFloat :: MyFloat(MyFloat & const obj)
{
size = obj.size;
arr = nullptr;
arr = new float [size];
for(int i = 0 ; i < obj.size; i++)
{
arr[i] = obj.arr[i];
}
}
MyFloat & MyFloat :: operator=(MyFloat & const obj)
{
size = obj.size;
arr = nullptr;
arr = new float [size];
for(int i = 0 ; i < obj.size; i++)
{
arr[i] = obj.arr[i];
}
return *this;
}
void MyFloat :: PrintFloat()
{
for(int i = 0 ; i < size; i++)
{
cout << arr[i];
}
cout << endl;
}
MyFloat::~MyFloat()
{
if(arr != nullptr)
{
delete [] arr;
}
size = 0;
}
////Cpp file having mian()
#include"My_Floats_Header.h"
int main()
{
MyFloat *floatNumber = new MyFloat(5);//declaration
floatNumber -> input();//taking input
MyFloat newfloatNumber = *floatNumber;
floatNumber = rotate_right(floatNumber);
cout << "My Float without Rotation: ";
newfloatNumber.PrintFloat();
cout << "My Float after Rotation: ";
floatNumber -> PrintFloat();
system ("pause");
return 0;
}
ERRORS THAT I'm GETTING:
Error C4430 missing type specifier - int assumed. Note: C++ does not support default-int (in line number 4)
Error C2146 syntax error: missing ';' before identifier 'rotate_right' (in line number 4)
Error C2143 syntax error: missing ';' before '{' (in line number 5)
Error C2447 '{': missing function header (old-style formal list?) (in line number 5)
Error C2143 syntax error: missing ';' before '&' (in line number 40)
Error C4430 missing type specifier - int assumed. Note: C++ does not support default-int (in line number 40)
Error C2086 'int MyFloat': redefinition (in line number 40)
Error C2761 'MyFloat &MyFloat::operator =(MyFloat &)': member function redeclaration not allowed (in line number 41)
Error C2059 syntax error: '{' (in line number 41)
Error C2143 syntax error: missing ';' before '{' (in line number 41)
Error C2447 '{': missing function header (old-style formal list?) (in line number 41)
Error C4430 missing type specifier - int assumed. Note: C++ does not support default-int (in line number 4)
Error C2146 syntax error: missing ';' before identifier 'rotate_right' (in line number 4)
Error C2143 syntax error: missing ';' before '{' (in line number 5)
Error C2447 '{': missing function header (old-style formal list?) (in line number 5)
Error C2065 'floatNumber': undeclared identifier (in line number 6)
Error C2061 syntax error: identifier 'MyFloat' (in line number 6)
Error C2065 'floatNumber': undeclared identifier (in line number 7)
Error C2227 left of '->input' must point to class/struct/union/generic type (in line number 7)
Error C2146 syntax error: missing ';' before identifier 'newfloatNumber' (in line number 8)
Error C2065 'newfloatNumber': undeclared identifier (in line number 8)
Error C2065 'floatNumber': undeclared identifier (in line number 8
)
Error C2065 'floatNumber': undeclared identifier (in line number 9)
Error C2065 'newfloatNumber': undeclared identifier (in line number 12)
Error C2228 left of '.PrintFloat' must have class/struct/union (in line number 12)
Error C2065 'floatNumber': undeclared identifier (line number 15)
Error C2227 left of '->PrintFloat' must point to class/struct/union/generic type (line number 15)
MyFloat rotate_right() probably shouldn't be in a header file. If you take it out, you should resolve (most? all?) of your errors.
My recommendation would be to make it a static method of MyFloat.
As an alternative, you could keep rotate_right() as a standalone function, and simply #include "MyFloat.h at the top of your .cpp file.
In the header file, move the class definition above the definition of rotate_right(). This will get you closer to working code. Order matters.

Two questions with base64 encoding

I confused how to convert const char * to base64 with 2 Questions:
Question #1 how do I defined the length of output string that would perfectly match the length of output base64?I have found a code which from apple opensource,the code in below http://www.opensource.apple.com/source/QuickTimeStreamingServer/QuickTimeStreamingServer-452/CommonUtilitiesLib/base64.c
or I could directly use "atlenc.h" in VC++.if the length of coded_dst which I have defined is smaller than the actually,the program may crashed
int Base64encode(char *coded_dst, const char *plain_src, int len_plain_src)
{
const char basis_64[] ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int i;
char *p;
p = coded_dst;
for (i = 0; i < len_plain_src - 2; i += 3) {
*p++ = basis_64[(plain_src[i] >> 2) & 0x3F];
*p++ = basis_64[((plain_src[i] & 0x3) << 4) |
((int) (plain_src[i + 1] & 0xF0) >> 4)];
*p++ = basis_64[((plain_src[i + 1] & 0xF) << 2) |
((int) (plain_src[i + 2] & 0xC0) >> 6)];
*p++ = basis_64[plain_src[i + 2] & 0x3F];
}
if (i < len_plain_src) {
*p++ = basis_64[(plain_src[i] >> 2) & 0x3F];
if (i == (len_plain_src - 1)) {
*p++ = basis_64[((plain_src[i] & 0x3) << 4)];
*p++ = '=';
}
else {
*p++ = basis_64[((plain_src[i] & 0x3) << 4) |
((int) (plain_src[i + 1] & 0xF0) >> 4)];
*p++ = basis_64[((plain_src[i + 1] & 0xF) << 2)];
}
*p++ = '=';
}
*p++ = '\0';
return p - coded_dst;
}
Question #2 as we all well know that the type of byte in C++ is unsigned char,how do I convert the char * to unsigned char *?
thanks
regards
Ken
The design of your function, based on the signature, tells me it's up to the caller to provide a sufficient buffer for output. This would be unsafe in your example because the caller isn't informing the function how large that buffer is. Your function has no chance to limit output to coded_dst to the buffer provided, so you should add, at the least, a parameter for that.
As such, you would need to check as you loop to be sure p, a pointer into coded_dst, stays within that limit, returning an error to the caller if there's insufficient room.
That said, notice how many increments of p occur for every 3 source items processed. The ratio is 3/4...for every 3 that go into that loop, 4 come out. So, to start the calculation of the required length, begin with
( len_plain_src / 3 ) * 4;
Now, consider r = len_plain_src % 3; If r is zero, your algorithm adds 2 more bytes. If r has a remainder, your algorithm adds 3 more bytes.
After that, you append a zero terminator.
Look carefully, I've not clearly analyzed this, but you may have an error in the closing '=' appended at the tail for the case where (i<len_plain_src) - you may have added two of them instead of just one.
Now, to handle the unsigned char, you could change the declaration and initial assignment of p with,
unsigned char * p = (unsigned char *) coded_dst;
At which point it would be more convenient for you if you declare basis_64 to be unsigned char

Resources