Issues with strings and char arrays in C++ - c++

I'm writing a registry generator as a part of a bigger program. I'm very new in C++, but good at other programming languages like PHP.
I'll start by providing the code of the problematic function:
void generacionAleatoria() {
string r_marca, r_nom, r_apellido;
char r_patente[6];
int num_rand;
registroAuto r_auto;
string nombres[8] = {
"Juan", "Pedro", "Roberto", "Miguel", "Guillermo", "Emilio", "Roque", "Gustavo"
} ;
string apellidos[8] = {
"Messi", "Maradona", "Gardel", "Heredia", "Pimpinela", "Nadal", "Mascherano", "Troilo"
};
string marcas[12] = {
"Volvo", "Renault", "Audi", "Ford", "Fiat", "Chevrolet", "Nissan", "Volkswagen", "Mercedes Benz", "Rolls Royce", "Delorean", "Aston Martin"
};
char letras_patentes[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char numeros_patentes[] = "0123456789";
for (int i = 0; i < cantidad_autos; i++) {
r_marca = marcas[rand() % (sizeof(marcas)/sizeof(marcas[0]) - 1)];
r_nom = nombres[rand() % (sizeof(nombres)/sizeof(nombres[0]) - 1)];
r_apellido = apellidos[rand() % (sizeof(apellidos)/sizeof(apellidos[0]) - 1)];
for(int m = 0; m < 3; ++m) {
r_patente[m] = letras_patentes[rand() % (sizeof(letras_patentes) - 1)];
}
for(int n = 3; n < 6; n++) {
r_patente[n] = numeros_patentes[rand() % (sizeof(numeros_patentes) - 1)];
}
strcpy(r_auto.patente,r_patente);
strcpy(r_auto.marca,r_marca.c_str());
strcpy(r_auto.apellido,r_apellido.c_str());
strcpy(r_auto.nom,r_nom.c_str());
fwrite(&r_auto,sizeof(registroAuto),1,archivo);
if (ver_variables_testeo) {
//cout << (i+1) << ") " << r_auto.patente<<endl;
cout << (i+1) << ") " << r_auto.marca << " - " << r_auto.patente << " - " << r_auto.nom << " " << r_auto.apellido << endl; //Para testear
}
}
}
This creates 100 structs of the following type:
struct registroAuto {
char marca[15];
char patente[6];
char nom[25];
char apellido[25];
};
In case you're wondering, this is meant to be a registry of Uber drivers and their cars: brand, license plate, name and surname. Well, it's not really a registry, it's college homework.
The problem is that when I print out the contents of my new struct, the license plate and the name will be together, as in:
100) Fiat - KWQ293Maria - Maria Gardel
You can see by the position of the hyphens, that the license plate is now "KWQ293Maria", even though it is an array of 6 chars!
A reminder of the cout command:
cout << (i+1) << ") " << r_auto.marca << " - " << r_auto.patente << " - " << r_auto.nom << " " << r_auto.apellido << endl;
I did some tests, but I don't know what to do with the results.
1: commenting out the strcopy of the name fixes the issue
strcpy(r_auto.patente,r_patente);
strcpy(r_auto.marca,r_marca.c_str());
strcpy(r_auto.apellido,r_apellido.c_str());
//strcpy(r_auto.nom,r_nom.c_str());
As you can see, this is the last of the 4 statements in my original code, so I don't know why it would affect r_auto.patente.
Can you please help me? I'm guessing there's a key concept of char array handling that I missed out on in class :-(

When using character arrays as strings they need to be terminated by a null character '\0'. So when you construct your number-plate you need to make the array 7 characters long.
struct registroAuto {
char marca[15];
char patente[7]; // 6 for numbers, 1 for terminator '\0'
char nom[25];
char apellido[25];
};
Same with your working variable:
char r_patente[7];
And you need to manually add the null-terminator when you create the number:
for(int m = 0; m < 3; ++m) {
r_patente[m] = letras_patentes[rand() % (sizeof(letras_patentes) - 1)];
}
for(int n = 3; n < 6; n++) {
r_patente[n] = numeros_patentes[rand() % (sizeof(numeros_patentes) - 1)];
}
r_patente[6] = '\0'; // add the null terminator

Related

How to use CRT batch technique in Microsoft SEAL 3.1?

Can you please tell me whether SEAL 3.1 supports PolyCRTBuilder class? I am trying to run the following program but failed because the class is not declared in this scope.
/**
Suppose I have two arrays x = [1,2,3,4,5] and xMean = [3,3,3,3,3]. I composed and encrypted the two array using PolyCRTBuilder ( xCiphertext and xMeanCiphertext ) . If I subtract the two ciphertexts ( xCiphertext MINUS xMeanCiphertext ), I should get xResult = [-2, -1, 0, 1, 2] but after the homomorphic subtraction I am getting xResultDecrypted = [40959, 40960, 0 ,1, 2] . I can relate the overflow result to the plain modulus set but is there a work around for this problem. Here is the code:
*/
#include <iostream>
#include "seal/seal.h"
using namespace std;
using namespace seal;
/*
Helper function: Prints the parameters in a SEALContext.
*/
void print_parameters(shared_ptr<SEALContext> context)
{
// Verify parameters
if (!context)
{
throw invalid_argument("context is not set");
}
auto &context_data = *context->context_data();
/*
Which scheme are we using?
*/
string scheme_name;
switch (context_data.parms().scheme())
{
case scheme_type::BFV:scheme_name = "BFV";
break;
case scheme_type::CKKS:scheme_name = "CKKS";
break;
default:
throw invalid_argument("unsupported scheme");
}
cout << "/ Encryption parameters:" << endl;
cout << "| scheme: " << scheme_name << endl;
cout << "| poly_modulus_degree: " << context_data.parms().poly_modulus_degree() << endl;
/*
Print the size of the true (product) coefficient modulus.
*/
cout << "| coeff_modulus size: " << context_data.
total_coeff_modulus_bit_count() << " bits" << endl;
/*
For the BFV scheme print the plain_modulus parameter.
*/
if (context_data.parms().scheme() == scheme_type::BFV)
{
cout << "| plain_modulus: " << context_data.
parms().plain_modulus().value() << endl;
}
cout << "\\ noise_standard_deviation: " << context_data.
parms().noise_standard_deviation() << endl;
cout << endl;
}
int main(){
cout << "\nTotal memory allocated from the current memory pool: "<< (MemoryManager::GetPool().alloc_byte_count() >> 20) << " MB" << endl;
EncryptionParameters parms(scheme_type::BFV);
//EncryptionParameters parms;
parms.set_poly_modulus_degree(4096);
parms.set_coeff_modulus(coeff_modulus_128(4096));
parms.set_plain_modulus(40961); ////Make the coefficient modulus prime>2n to enable CRT batching
auto context = SEALContext::Create(parms);
print_parameters(context);
IntegerEncoder encoder(parms.plain_modulus());
KeyGenerator keygen(context);
PublicKey public_key = keygen.public_key();
SecretKey secret_key = keygen.secret_key();
// SEALContext context(parms);
// KeyGenerator keygen(context);
// auto public_key = keygen.public_key();
// auto secret_key = keygen.secret_key();
Encryptor encryptor(context, public_key);
Evaluator evaluator(context);
Decryptor decryptor(context, secret_key);
PolyCRTBuilder crtbuilder(context);
int slot_count = crtbuilder.slot_count();
int row_size = slot_count / 2;
vector<uint64_t> x_pod_matrix(slot_count, 0);
x_pod_matrix[0] = 1;
x_pod_matrix[1] = 2;
x_pod_matrix[2] = 3;
x_pod_matrix[3] = 4;
x_pod_matrix[4] = 5;
Plaintext x_plain_matrix;
crtbuilder.compose(x_pod_matrix, x_plain_matrix);
Ciphertext x_encrypted_matrix;
encryptor.encrypt(x_plain_matrix, x_encrypted_matrix);
vector<uint64_t> x_mean_pod_matrix(slot_count, 0);
x_mean_pod_matrix[0] = 3;
x_mean_pod_matrix[1] = 3;
x_mean_pod_matrix[2] = 3;
x_mean_pod_matrix[3] = 3;
x_mean_pod_matrix[4] = 3;
Plaintext x_mean_plain_matrix;
crtbuilder.compose(x_mean_pod_matrix, x_mean_plain_matrix);
Ciphertext x_mean_encrypted_matrix;
encryptor.encrypt(x_mean_plain_matrix, x_mean_encrypted_matrix);
evaluator.sub_plain(x_encrypted_matrix, x_mean_encrypted_matrix);
// Decrypt x_encrypted_matrix
Plaintext x_plain_result;
decryptor.decrypt(x_encrypted_matrix, x_plain_result);
vector<uint64_t> pod_result;
crtbuilder.decompose(x_plain_result, pod_result);
for(int i = 0; i < 5; i++) {
std::cout << pod_result[i] << '\n';
}
return 0;
}
PolyCRTBuilder has been renamed to BatchEncoder. Take a look at the src/examples directory in SEAL v3.1 (or native/examples in a newer version) and you'll see plenty of examples.
Kind of related to your question: the coeff_modulus_128 function hasn't existed in SEAL for quite a while; the same functionality is provided by the CoeffModulus::BFVDefault function. With these changes your code might work in SEAL 3.5 even.

Writing a Hash Table to File and Restoring From File in C++

I am working on an assignment for school using hash tables in a structure program. Part of the assignment is writing a hash table composed of 20 primary buckets and 10 overflow buckets, each with 3 slots composed of a key and data field to disk and then restoring from it. Here is what I have so far:
#include <iostream>
#include <fstream>
#include <iomanip>
#include <stdio.h>
#include <string.h> // for strcpy()
using namespace std;
typedef char STR10[10+1];
typedef char STR20[20+1];
struct SLOT
{
STR10 key;
STR20 data;
};
struct BUCKET
{
SLOT entry[3];
int count;
BUCKET* overflow;
};
struct HASHTABLE
{
BUCKET pBkt[20];
BUCKET oBkt[10];
};
void WriteHTtoDisk (HASHTABLE ht, char *HashDisk);
void ReportHT (HASHTABLE ht, char * when);
int main()
{
int maxP = 20;
int maxO = 10;
int maxS = 3;
HASHTABLE ht;
STR10 mKey;
STR20 mData;
FILE * inFile;
inFile = fopen("DATAIN.dat","rb");
if (inFile == NULL)
{
cout << " DATAIN file access error ... \n";
cout << " Terminating application ... \n ";
cout << " Press any key ... \n ";
return -100;
}
char crLF;
while (!feof(inFile))
{
fscanf(inFile,"%10c%20c\n",mKey,mData);
mKey[10] = mData[20] = 0; // add string terminators
printf(" MyKey: %10s\n MyData: %20s\n",mKey,mData);
cin.ignore(80,'\n'), cin.get();
//InsertIntoHT (ht, mKey, mData);
}
fclose(inFile);
WriteHTtoDisk(ht, "hashTable.dat");
ReportHT (ht,"BEFORE");
return 0;
}
void WriteHTtoDisk (HASHTABLE ht, char *HashDisk)
{
FILE * HASHDISK = fopen(HashDisk, "rb");
int maxBkt = 30;
int maxSlot = 3;
for (int i = 0; i < maxBkt; i++)
{
for (int j = 0; j < maxSlot; j++)
{
fwrite(ht.pBkt[i].entry[j].key,11,sizeof(maxSlot),HASHDISK);
fwrite(ht.pBkt[i].entry[j].data,21,sizeof(maxSlot),HASHDISK);
}
}
}
void ReportHT (HASHTABLE ht, char * when)
{
int maxB = 30;
int maxS = 3;
cout << "Hash Table \n" << "Verification Report \n" << when << " Restoration" << endl;
for (int b = 0; b < maxB; b++)
{
cout << "Bucket " << (b+1) << endl;
if (b < 20)
{
for (int i = 0; i < maxS; i++)
{
cout << setw(3) << "Slot " << (i+1) << ": " << ht.pBkt[b].entry[i].key << setw(3) << ht.pBkt[b].entry[i].data << endl;
}
}
else
{
for (int i = 0; i < maxS; i++)
{
cout << setw(3) << "Slot " << (i+1) << ": " << ht.oBkt[b].entry[i].key << setw(3) << ht.oBkt[b].entry[i].data << endl;
}
}
}
}
The code compiles with no problems, but when I inspect the file, I find that it is all just gibberish and weird symbols. The data I am using was previously extracted from another file and I want to save it in the format in which it was inserted. I am sure the issue is with the lines with fwrite (I am not that experienced with C syntax as I am with C++).
The data was in the DATAIN.dat file like this:
TATUNG CO.EL PR. LONG BEACH CA
KAMERMAN LCIRRUS BEAVERTON, OR
QUADRAM COLOACH AV NORCROSS GE
AST RESEARALTON AV IRVINE CA
I am expecting the new file to look like this:
TATUNG CO.
EL PR. LONG BEACH CA
KAMERMAN L
CIRRUS BEAVERTON, OR
QUADRAM CO
LOACH AV NORCROSS GE
AST RESEAR
ALTON AV IRVINE CA
Any help would be greatly appreciated. Thank you.
It looks like your code doesn't initialize or even use the member count. When a hash bucket is empty, the count should indicate it. In C++ it's easy to implement: just add = 0 to its definition:
struct BUCKET
{
SLOT entry[3];
int count = 0;
BUCKET* overflow;
};
Also, when writing the bucket's data to a file, use the count and don't assume that all the entries in the bucket are filled.
for (int j = 0; j < ht.pBkt[i].count; j++)
...
Also, write only the required number of bytes. fwrite accepts two parameters: the size of the data elements to write and their number. Here, the size is 11 or 21, and the number is 1, because each fwrite call can only write one string to your file.
fwrite(ht.pBkt[i].entry[j].key,11,1,HASHDISK);
fwrite(ht.pBkt[i].entry[j].data,21,1,HASHDISK);
By the way, since you have a STR10 type, you can avoid magic numbers and write sizeof(STR10) instead of 11. This way, when you change the length of your string, your code will still work.

Using CheckSum with C++ for 13 Digit ISBN

I am trying to calculate the final digit of a 13 digit ISBN using the first 12 digits using C++. I feel like my code should be correct but I have a feeling the formula I'm using may be wrong.
The formula is:
10 - (d0 + d1 * 3 + d2 + d3 * 3 + d4 + d5 * 3 + d6 + d7 * 3 + d8 + d9 * 3 + d10 + d11 * 3) % 10
Here's what I have:
#include <cstring>
#include <iostream>
int main() {
int weightedSum = 0;
int checksum = 0;
int i; //for loop decrement
int mul = 3;
const int LENGTH = 12;
char ISBNinput[LENGTH];
std::cout << "Enter first 12 digits of ISBN: "; //ask user for input
std::cin >> ISBNinput; //stores input into ISBNinput
std::cout << std::endl;
for (i = 0; i < strlen(ISBNinput); i++) {
weightedSum += (ISBNinput[i] % 12) * mul;
if (mul == 3) {
mul = 1;
} else {
mul = 3;
}
}//close for loop
checksum = weightedSum % 10; //calculates checksum from weightedSum
std::cout << checksum << std::endl; //prints checksum with new line for format
return 0;
}
For example:
978007063546 should return 3
and
978032133487 should return 9
Thank you for any help.
Here's how I go about this.
First, let's decide how we're going to test this. I'll assume that we've written the function, and that it gives the correct output. So I pick up a couple of books off my desk, and test that it works for them:
#include <iostream>
int main()
{
std::cout << "Book 1 - expect 3, got " << checksum("978032114653") << std::endl;
std::cout << "Book 2 - expect 0, got " << checksum("978020163361") << std::endl;
}
Of course, when we try to compile that, we get an error. So create the function, before main():
char checksum(const char *s)
{
return '1';
}
Now it compiles, but the result is always 1, but now we can start to fill in the body. Let's start with some smaller examples, that we can calculate by hand; add these at the beginning of main():
std::cout << "1 digit - expect 4, got " << checksum("6") << std::endl;
Now let's get this one working - this gives us conversion from character to digit and back, at least:
char checksum(const char *s)
{
int digit = *s - '0';
return '0' + 10 - digit;
}
Let's try 2 digits:
std::cout << "1 digit - expect 6, got " << checksum("11") << std::endl;
And now our test fails again. So add some more processing, to make this pass (and not break the single-digit test):
char checksum(const char *s)
{
int sum = 0;
int digit = *s - '0';
sum += digit;
++s;
if (*s) {
digit = *s - '0';
sum += 3 * digit;
}
return '0' + (10 - sum)%10;
}
We're probably ready to make this into a loop now. Once that's passed, we no longer need the short tests, and I have:
#include <iostream>
char checksum(const char *s)
{
int sum = 0;
for (int mul = 1; *s; ++s) {
int digit = *s - '0';
sum += mul * digit;
mul = 4 - mul;
}
return '0' + (1000 - sum)%10;
}
int test(const char *name, char expected, const char *input)
{
char actual = checksum(input);
if (actual == expected) {
std::cout << "PASS: " << name << ": "
<< input << " => " << actual
<< std::endl;
return 0;
} else {
std::cout << "FAIL: " << name << ": "
<< input << " => " << actual
<< " - expected " << expected
<< std::endl;
return 1;
}
}
int main()
{
int failures = 0;
failures += test("Book 1", '3', "978032114653");
failures += test("Book 2", '0', "978020163361");
return failures > 0;
}
I factored out the actual checking into a function here, so we can keep count of failures, and exit with the appropriate status, but everything else is as I described above.
You'll want to add a few more test cases - in particular, make sure the function correctly returns the extreme values 0 and 9 when it should.
There is one clear bug in your code: you are not allocating enough space in for ISBNinput. You should make it one character longer:
const int LENGTH = 13;
The reason for this is that that character-array strings are terminated with an extra null character. You might be lucky and the next byte in memory could sometimes happen to be a null byte, in which case the program would still work sometimes.
If you run the program with valgrind or a similar memory checker you are likely to see an error as the program access memory beyond what was allocated on the stack.
Also I think there is another bug. I think that mul should be initialized to 1.
By the way, this code is very fragile, depending on you entering no more than 12 characters, all of which are assumed to be digits. It might be OK as a quick hack for a proof-of-concept, but should not be used in any real program.

How did this memory corruption occur in c++?

I'm not sure I understand what the bug below is
const char* packs[] = {"zero","one","two","three","four",..."twelve"} //abbreviated for post
struct packinfo {
char* data;
int len;
};
std::vector<packinfo> k;
k.reserve(10000);
for (int i = 0; i < 10; ++i) {
const char* data = packs[i];
packinfo tobuf;
tobuf.data = new char[strlen(data)];
tobuf.len = strlen(data);
memcpy(tobuf.data, data, strlen(data));
k.push_back(tobuf);
}
for (int i = 0; i < k.size(); ++i)
std::cout << "k[" << i << "]: " << k[i].data << ", ";
std::cout << std::endl;
for (int i = 0; i < k.size(); ++i) {
packinfo& pack = k[i];
bool foo = (i < 5);
if (foo) std::cout << "inspecting k[" << i << "]: " << k[i].data << std::endl;
delete pack.data;
if (!foo) {
k.erase(k.begin(), k.begin() + i);
packinfo tobuf;
const char* data = packs[10];
tobuf.data = new char[strlen(data)];
tobuf.len = strlen(data);
memcpy(tobuf.data, data, strlen(data));
break; //intentionally forgot to push_back
}
}
for (int i = 0; i < k.size(); ++i)
std::cout << "k[" << i << "]: " << k[i].data << ", ";
std::cout << std::endl
;
The output of running the above is the following:
k[0]: zero, k[1]: one, ... , k[9]: nine, //all as expected
inspecting k[0]: zero
inspecting k[1]: one
...
inspecting k[4]: four
k[0]: ten^], k[1]: six, k[2] seven, k[3]: eight, k[4]L nine, //gargabe crept in
How did garbage creep into the beginning of the vector?
strlen gives you the length of characters in a nul-terminated string wihtout counting the nul-termination character. So you are dynamically allocating a data buffer that is too short to hold the target string:
tobuf.data = new char[strlen(data)]; // too short by 1
When you fill it using memcpy, there is no space for a null-termination for the string, and you wouldn't copy it if there was anyway, because the array is too short:
memcpy(tobuf.data, data, strlen(data)); // tobuf.data is not nul-terminated
When you attempt to read it as if it were a nul terminated string, you go out of bounds.
The immediate fix would be to use strlen(data) +1, but what you really should do is avoid the whole problem by replacing packinfo by std::string.
std::vector<std::string> k;
k.reserve(10000);
The problem is these lines:
tobuf.data = new char[strlen(data)];
tobuf.len = strlen(data);
memcpy(tobuf.data, data, strlen(data));
Where do you add space for the string terminator?
C++ have the std::string class, you should really use it as it will help you with these kind of problems.

My buffer contains elements, but aren't being printed

Sorry scratch my last post, it's way to late =S
But basically I'm having problems sending out the buffer I created. Just need to know where I'm going wrong =( or if theres a better way.
------ Client Sending Username -------
int bufferSize = 32;
char messageBuffer[bufferSize];
char* message;
if (userName.size() > 8)
{
cout << "Invalid username : Greater than 8 characters" << endl;
}
else
{
switch(regType)
{
case(REGISTER):
{
cout << "Registered name: " << userName << endl;
messageBuffer[0] = 1;
messageBuffer[1] = 0;
for (int i = 2; i < (userName.size() + 2); i++)
{
messageBuffer[i] = userName[(i - 2)];
}
for (int i = 0; i < (userName.size() + 2); i++)
{
cout << messageBuffer[i];
}
cout << "<<<< messageBuffer " << endl;
message = &messageBuffer[0];
cout << messageBuffer << endl;
//message[(userName.size() + 2)] = '\0';
int messageLen = userName.size() + 2;
if (send(sock, messageBuffer, messageLen, 0) != messageLen)
DieWithError("send() send an invalid name");
}break;
case(UNREGISTER):
{
}break;
}
}
----------- Server (Receiver)------------
char msgRcvBuffer[RCVBUFSIZE];
int recvMsgSize;
if ((recvMsgSize = recv(clntSocket, msgRcvBuffer, RCVBUFSIZE, 0)) < 0)
DieWithError("recv() failed");
msgRcvBuffer[recvMsgSize] = '\0';
string msgType( msgRcvBuffer );
cout << "Message Type " << msgType << endl; <<<<<< Nothing appears when printed
void handleReg(string message, int socket, string ipAddr)
{
// Remove the Prefix
int startIndex = 2;
// Get the username from the message
string userName = message.substr(startIndex, message.size() - startIndex);
cout << "Username " << userName << endl;
For some reason my message string is just 1... =S What i'm trying to do is just get the message from what was sent from client. I'm just tryin to remove the '1' and '0' from the beginning of the buffer. 1 and 0 aren't characters.
Thanks so much for everyones help =)
The conversion from char* to string treats the string as null-terminated. This doesn’t seem to be the case here – in particular, your char array appears to contain 0 characters, so the string will be cut off at this position.
To circumvent this, you need to pass the valid range of characters to the string constructor, in place of only the start pointer:
msgType = string(msgRcvBuffer, msgRcvBuffer + recvMsgSize);
If msgRcvBuffer is of size RCVBUFSIZE then msgRcvBuffer[recvMsgSize] = '\0'; is going to be writing beyond the end of the buffer I think.
Use the std::string constructor that takes a buffer and buffer size parameter:
msgType = std::string(msgRcvBuffer, recvMsgSize);