I have an assignment to create a block transposition cipher program. A user is to input a phrase of their choice, and the program is to strip the phrase of spaces, punctuation, and make lowercase, before reading its length and creating a two-dimensional array the size of the nearest square that will fit all the chars in the mutated string, and filling in the remaining space with random letters.
Problem is, I'm having issues with creating that square.
I have this so far:
int main()
{
string input;
cout << "Please enter message to cipher." << endl;
getline(cin, input);
/* do punctuation removal/mutation */
int strLength = input.length(); //after mutation
/* need to find the square here before applying sizes and values to arrays */
char * original = new char[][]; // sizes pending
char * transposed = new char[][]; // sizes pending
for (int i = 0; i <= /* size pending */ ; i++)
{
for (int j = 0; j <= /* size pending */ ; j++)
{
transposed[j][i] = original[i][j];
}
}
/* do more stuff here */
}
any ideas?
(I already have done the mutation portion; tested with alternate code)
You can't do e.g.
char * original = new char[][];
First of all you are trying to create an array of arrays (or pointer of pointers) and assign it to a single pointer. You need to do it in two steps:
Allocate the "outer" array:
char **original = new char* [size];
Allocate the "inner" strings:
for (int i = 0; i < size; i++)
original[i] = new char [other_size];
However I would highly recommend against using that! Instead you should be using std::vector instead of "arrays" allocated on the heap, and if the contents are strings then use std::string:
std::vector< std::vector< std::string > > original;
You can take the square root of the length, round down to an integer, and add one to get the new length.
int len = (int)(sqrt(strLength) + 1e-9) + 1;
You'd then malloc the square using len and fill as you normally would.
I believe you do not need the "new" to create your storage. Following code should just do the job:
char buf[size][size]; // size is a variable
... // populate your buf
char tmp;
for(int i = 0; i < size; i++) {
for(int j = 0; j < i; j++) {
tmp = buf[i][j];
buf[i][j] = buf[j][i];
buf[j][i] = tmp;
}
}
This does the transpose in place. You don't need another array to store the char's.
Related
EDIT: I've solved the issue! It had nothing to do with the function itself. I initially used a vector for this function, and the cout statement I used to check the function in main() still called the vector, not the array. A simple mistake, but I appreciate the help!
Hey! I'm currently in college learning data structures, and for our final project, we're tasked with creating multiple sorting algorithms to sort 500,000 randomly generated numbers between 1 - 9,999,999 that have been defined in a text file. I'm currently trying to work on a counting sort, and I keep getting the #include vector line 1553 error 'vector subscript out of range'. I've debugged this function all the way to the last for-loop. Everything seems to work perfectly fine, so I'm assuming it has to do with somewhere in this final piece, but I'd prefer to not have to manually go through 500,000 cycles, so if anyone can see what I've done wrong, I'd like to know.
I also allocated this data on the heap because stack allocation creates a memory overload.
I apologize if this is a low-level question, but I'd love some help, as this project means a lot to me and to my grade. Thank you!
void countingSort(int numberArray[], int SIZE)
{
// Initializer for dynamically-allocated array used to hold the sorted data in the array
int* sortedArray = new int[SIZE];
// Initializes all values in sortedArray to 0
for (int i = 0; i < SIZE; i++)
sortedArray[i] = 0;
// Initializer for variable used to hold the maximum value in the original data
int max = 0;
// Finds the max in numberArray
for (int i = 0; i < SIZE; i++)
{
if (numberArray[i] > max)
max = numberArray[i];
}
// Create an array to store the amount of times each number in numberArray is used
int* countArray = new int[max + 1];
// Initialize all indexes of countArray to 0
for (int i = 0; i <= max; i++)
{
countArray[i] = 0;
}
// When a number is present in numberArray, increase its number of appearances in countArray by one
for (int i = 1; i < SIZE; i++)
countArray[numberArray[i]]++;
// Find the total frequency in the count array
for (int i = 1; i <= max; i++)
countArray[i] += countArray[i - 1];
// Store the sorted values into a sorted array
// Decrease the total count number
for (int i = SIZE - 1; i > 0; i--)
{
sortedArray[countArray[numberArray[i]] - 1] = numberArray[i];
countArray[numberArray[i]]--;
}
// Store the sorted array in the original numberArray
for (int i = 0; i < SIZE; i++)
{
numberArray[i] = sortedArray[i];
}
}
int main()
{
int* SIZE = new int;
*SIZE = 500000;
.
(*code for other functions*)
.
countingSort(numberArray, *SIZE);
cout << "\n" << numberList[0] << "\t" << numberList[499999] << endl;
}
In this code, an array of pointers newData is created in a for loop then it is pushed into a vector testData. The pointers are stored in the vector std::vector<testData*>.
My concern is that I need to make sure that the objects referenced by the pointers remain valid while the vector holds a reference to them. Do I lose this reference by calling the line newData = new unsigned char[frameSize]; in a for loop?
I mainly want to avoid copying the objects with a push_back.
How can I create an array of unsigned char* of random char (here I just use 'a') and then push these arrays to the vector?
int numFrames = 25;
int frameSize = 100;
std::vector<unsigned char*> testData;
unsigned char *newData;
for (int i = 0; i < numFrames; i++) {
newData = new unsigned char[frameSize];
for (int j = 0; j < frameSize; j++) {
newData[j] = 'a'; // fill the frame with random data, 'a' here
}
testData.push_back(newData);
newData = 0; // ??
memset(&newData, 0, frameSize); // ??
}
std::cout << " testData " << testData.size() << "\n";
Do I lose this reference by calling the line newData = new unsigned char[frameSize]; in a for loop?
No, if done correctly it's perfectly feasible.
The are some problems in your code though, in the line memset(&newData, 0, frameSize); // ?? you're setting the memory occupied by a pointer, which is usually no more than 8 bytes (depending on the architecture) with a size of 100 bytes, this invokes undefined behavior. You may wanted:
memset(&newData, 0, sizeof newData); // ??
But this wouldn't do what you need, nullifying the pointer would make you lose access to the data, you don't want that, and you are pushing the same pointer to the vector in each iteration, you'll end up with a vector filled with the same pointer pointing to the same data.
Moving its declaration inside the for loop would solve this. You're not copying any data, instead pushing a new pointer, pointing to a new memory location, into the vector, at each new iteration.
How can I create an array of unsigned char* of random char (here I just use 'a') and then push these arrays to the vector?`
Your code should look something like this:
Live demo
#include <iostream>
#include <vector>
#include <ctime>
int main()
{
srand(time(0)); //seed, not the best randomizer but does the job here
const size_t numFrames = 25; //sizes can/should be constant and unsigned
const size_t frameSize = 100;
std::vector<unsigned char *> testData;
for (size_t i = 0; i < numFrames; i++)
{
//in each iteration a new pointer
unsigned char *newData = new unsigned char[frameSize];
for (size_t j = 0; j < frameSize; j++)
{
newData[j] = 'a' + rand() % 26; //random alphabetic char
}
testData.push_back(newData);
}
std::cout << "testData " << testData.size() << "\n";
for (size_t i = 0; i < numFrames; i++) //test print
{
for (size_t j = 0; j < frameSize; j++)
{
std::cout << testData[i][j];
}
std::cout << "\n";
}
}
Needless to say you should delete the memory you previously allocated when you no longer need it.
If you want a better random engine you can check this post Generate random numbers using C++11 random library.
Some notes:
As you're probably aware the data pointed by newData pointers can't be treated as a string, aka, a null terminated char array because, of course, they're not null terminated.
You'll need to manually manage the memory you allocated, that is to say that the memory reserved manually will also have to be deleted manually, when you're done with it.
The code corrections are for your code as it is, but as WhozCraig correctly points out, you would probably be better off using STL containers all around instead of pointers.
I am writing code that finds the number of palindrome strings in a given array of strings. I think I have the right idea, but I am getting weird errors when I run it. What exactly am I doing wrong?
int countPalindromes(string s) {
int size = s.size();
int counter = 0;
string forwardSum = "";
string backwardSum = "";
for(int i = 0; i < size; i++){
for(int j = i; j < size; i++){
forwardSum.push_back(s[j]);
backwardSum.push_back(s[(n - 1)-j]);
if(forwardSum == backwardSum){
counter++;
}
}
}
return counter;
}
string forwardSum[] = {};
This is an array of zero size (which I don't believe is legal but we'll let that pass)
forwardSum[i] = forwardSum[i] + s[j];
This is an attempt to access the ith element of an array which has zero size.
That's bad.
I'm not really following your code (it's late at night), but I think you probably want forwardSum and backwardSum to be strings not arrays of strings. And you probably want to use push_back to add characters from s to those strings. I.e.
string forwardSum;
...
forwardSum.push_back(s[j]); // add s[j] to forwardSum
But if you really do want forwardSum to be an array, then the sensible thing to do would be to use a vector instead.
vector<string> forwardSum(size); // a vector of strings with the given size
Now that should at least not crash with the rest of your code.
I know eventually I need to change trigram, whose one space contains 3 characters from the former string, into a dynamic array to solve this problem, but I tried to set my array's capacity large enough at first. However, when I compile my code, the error appears.
#error: variable length array of non-POD element type 'string' (aka 'basic_string<char>'#
Code:
//global variable
int CAPACITY = 1000;
int main()
{
//a string that reads in the language of the text
string language = "";
//a string that reads in the file name of the text
string filename = "text.txt";
//a string that reads in the original text characters
string original = "";
//a string that reads in the modified original array
string rid_of_spaces = "";
//an array with capacity that stores the trigrams
string trigrams[CAPACITY];
ifstream finput;
char c;
//the length of an array
int sLength = 0;
//the tracker for trigrams
int counter = 0;
cin >> language >> filename;
finput.open(filename.c_str());
while (finput.get(c)){
//to test if the character is alpha
if (isalpha(c)){
//change the alphabet to lowercase
c = tolower(c);
//store the modified letter in the array
original += c;
}
//change any other characters into a space
else original += ' ';
}
sLength = original.length();
//loop through the original array and change mutiple spaces into one
for (int i = 0; i < sLength; i++){
if (isalpha(original[i]))
rid_of_spaces += original[i];
else {
while (original[i] == ' ')
i++;
rid_of_spaces += ' ';
rid_of_spaces += original[i];
}
}
sLength = rid_of_spaces.length();
for (int i = 0; i < CAPACITY; i++)
trigrams[i] = 0;//initialize each element to 0
for (int i = 0; i < sLength - 2; i++){
trigrams[counter] += rid_of_spaces[i]
+ rid_of_spaces[i + 1]
+ rid_of_spaces[i + 2];
counter++;
}
cout << filename << endl;
cout << original << endl;
cout << rid_of_spaces << endl;
for (int i = 0; i < counter; i++)
cout << trigrams[i] << endl;
finput.close();
return 0;
}
The variable
int CAPACITY = 1000;
should be a constant
const int CAPACITY = 1000; // or with c++11 constexpr int CAPACITY = 1000;
for
string trigrams[CAPACITY];
because "ISO C++ forbids variable length array 'trigrams'" (g++ message)
And this
for (int i = 0; i < CAPACITY; i++)
trigrams[i] = 0;//initialize each element to 0
should be
for (int i = 0; i < CAPACITY; ++i)
trigrams[i] = "";//initialize each element to 0
You don't "initialize [strings] to 0" but with a zero length C-string. A zero length C-string is not an invalid 0-pointer, but a (valid) pointer to a char with value 0;
Generally, it's better not to use C-arrays if there are STL-means to avoid them; with c++11, std::array<std::string, CAPACITY> would be preferable here if you want to stay with the "capacity large enough" approach.
live at Coliru's
I took the liberty to change all i++ to ++i in the for-loops' heads while at it; see eg. What is the difference between ++i and i++ for the rationale behind that.
For a dynamic (without pre-defined bounds) array use std::vector<std::string> trigrams;,
push_back or emplace_back your strings into that vector,
and for i- iterate
for (std::size_t i = 0; i < trigrams.size(); ++i) {/* ... */}
Or use the iterator-interface of std::vector, e.g.
std::for_each(trigrams.begin(), trigrams.end(),
some_function_or_functor_that_does_the_job);
(see std::foreach here ),
or with c++11 just
for (auto& s : trigrams) {/* ... */}
unless you need to customize the iteration like you do it inside your second loop.
The variable CAPACITY is not a compile-time constant variable, and variable-length arrays are not in C++ (though some have it as an extension, but apparently not for all types).
There are two solutions to your problem:
Turn the variable into a compile-time constant, either by making it constexpr alternatively const (for older compilers), or by defining it as a preprocessor macro.
Use std::vector, like std::vector<std::string> trigram(CAPACITY);
My suggestion is that you use both solutions above, at least if you later need to resize the vector. If the size will be fixed at compile-time and never change, then use the first solution and use std::array instead of a C-style array:
constexpr std::size_t CAPACITY = 1000;
...
std::array<std::string, CAPACITY> trigram;
The size of a C++ array must be a constant expression. You declare it as int CAPACITY = 1000;, which is not a constant expression. Adding a const qualifier solves the issue: int const CAPACITY = 1000;.
However, you should avoid plain arrays. Try using std::array if you know the size at compile time, or std::vector if not.
I have a simple table called mytable2 with only one column, name as varchar2(20).
I now have a list of names stored as vector of std::string to be inserted into the table.
I want to use executeArrayUpdate, so I must do the setDataBuffer first.
However, as I could see, people always use char[][20] to set databuffer.
This leaves me a big headache, since I have two issues here, first is to convert from vector to array, second is to convert the string to char.
1st, I tired to use vector of char[20], and this doesn't compile. Googled and they say that vector can't take char[], so I changed my vector of std::string to vector of char*.
2nd, I tried to turn the vector to arrray by using "void* p=&names[0]", as some people say this way we can use vectors just as array.
I used stmt->setDataBuffer(1,mystring,OCCI_SQLT_STR,20,NULL), and the program compiled and executed alright, but when I "select name from mytable2", it showed only some strange charaters.
Anyone has had a similiar issue before? what should I do?
My code is simple as below:
count=2;
vector<char*> mystring;
for(int i=0;i<count;i++)
{
char my[20];
strcpy_s(my,"Michael");
mystring.insert(mystring.end(),my);
}
stmt->setDataBuffer(1,&mystring[0],OCCI_SQLT_STR,20,NULL);
stmt->setBatchErrorMode (true);
stmt->executeArrayUpdate(count);
You'd need to dynamically create the char array you're putting into the vector for it to have a chance of working correctly.
I have not used OCCI, but if I had to use API that asked for char[][20], I would give it char[][20]
If you have your existing data in vector, why not just copy it across into the 2D char array? Eg.
// intialise vector with nonsense
unsigned int const VEC_SIZE = 2 ;
vector<string> v;
for (unsigned int i = 0; i < VEC_SIZE; ++i) {
stringstream s;
s << "Jon Paul " << i << endl;
v.push_back ( s.str() ) ;
}
// create the required 2D char array
unsigned int const STR_LEN = 20 ;
char c [VEC_SIZE][STR_LEN];
// copy the data from the vector of strings to the 2D char array
for (unsigned int i = 0; i < VEC_SIZE; ++i) {
string s = v[i].substr(0,STR_LEN);
char const * const cc = s.c_str();
unsigned int j = 0;
for (; j < STR_LEN && j < s.size(); ++j) {
c[i][j] = cc[j];
}
c[i][ j==STR_LEN ? 20 : j ] = 0; // write NULL character
}
I take it you've simplified your example to be a fixed size vector, so my response is going to be simplified to, with the thorny issue of dynamic allocation of 2D arrays left as an exercise for the reader...