I've only recently taken up C++ and am having difficulty shifting array elements to remove empty/null elements
char *aBlock;
aBlock = new char[100];
int main(int argc, char **argv)
{
aBlock[20] = 'a'; // fill array with test data.
aBlock[10] = 's';
aBlock[30] = 'd'; // Excepted output: This test data should be shifted to the start of array
// Consider aBlock contains data, with random empty elements
for(int i=1; i <= aBlock.length(); i++) {
if(aBlock[i-1] == 0) {
aBlock[i-1] = aBlock[i];
aBlock[i] = 0;
}
}
return 0;
}
Edit:
Fixed a code typo & wrong variable names, changed "==" to "=".
It still doesn't work as expected.
If I understood correctly, you want to move the non-zero elements at the beginning of your array. You could use std::remove_if to do this and set the rest of the elements to 0.
std::fill(
std::remove_if(std::begin(aBlock), std::end(aBlock), [](char const c) {return c == '\0'; }),
std::end(aBlock),
0);
UPDATE:
Since the array is dynamically allocated you need a small change:
std::fill(
std::remove_if(&aBlock[0], &aBlock[100], [](char const c) {return c == '\0'; }),
&aBlock[100],
0);
Operator == checks the equality, you must use = to assign.
memBlock[i-1] = memBlock[i];
Arrays in C++ have not any member like .length(). They are not classes.
for(int i=1; i <= 100; i++)
^^^
If you know the size at compile-time, use std::array if available. Then you can do ".size()" :) Also, your code doesn't work if you have several consecutive zeroes. Every element is shifted to the left at most once, which is clearly insufficient to achieve your desired result. What you need to do is keep track of a separate "output" index/iterator which receives any non-zero value you encounter and is then incremented:
std::array<char, 100> aBlock;
aBlock[10] = 's';
aBlock[20] = 'a';
aBlock[30] = 'd';
auto output = aBlock.begin(); // or aBlock if you don't have std::array;
for (auto input = aBlock.begin(); input != aBlock.end(); ++input)
{
if (*input != 0)
{
if (output != input)
{
*output = input;
*input = 0;
}
++output;
}
}
That should do the trick.
int arrsize = 100;
...
int i, j;
for(i = 0, j = 0; i < arrsize ; i++) {
if(memBlock[i] != 0 && i != j) {
memBlock[j++] = memBlock[i];
memBlock[i] = 0;
}
}
Side note: new in global space? And where is delete[] ?
change
memBlock[i-1] == memBlock[i];
to
memBlock[i-1] = memBlock[i];
"==" is the problem i think.
use
if(aBlock[i-1] != 0)
Related
I've been running into this weird issue where the split code returns correctly when I printf output inside the function, but will incorrectly return output upon calling it as an instance.
Question: How do I get the correct ouput when calling it as an instance?(see useage bellow)
Here is the code:
typedef struct SplitText
{
int splitLen;
char* splitTxt[100];
char* subTxt(char* text, int index, int len)
{
char subTxt_[1000];
int count = 0;
for (int i = 0; i < 1000; i++)
subTxt_[i] = '\0';
for (int i = index; i < index + len; i++)
subTxt_[count++] = text[i];
return subTxt_;
}
void split(char* text, char sep)
{
char separator[3] = { '<', sep, '>' };
int textLen = strlen(text);
int splitIndex = 0;
int splitCount = 0;
for (int t = 0; t < textLen; t++)
{
if (text[t] == separator[0] && text[t + 1] == separator[1] && text[t + 2] == separator[2])
{
if (splitIndex != 0)
splitIndex += 3;
splitTxt[splitCount] = subTxt(text, splitIndex, t - splitIndex);
splitIndex = t;
//correct output
printf(splitTxt[splitCount]);
printf("\n");
splitCount++;
}
}
splitLen = splitCount;
}
}SplitText;
Useage:
SplitText st;
st.split("testing<=>split<=>function<=>", '=');
for (int i = 0; i < st.splitLen; i++)
{
//incorrect output
printf(st.splitTxt[i]);
printf("\n");
}
printf("--------\n");
This:
char* subTxt(char* text, int index, int len)
{
char subTxt_[1000];
...
return subTxt_;
}
Is undefined behavior. Returning a pointer to a local stack variable (or local array var) is going to result in weird stuff like this happening.
The typical thing that corrupts the contens of that returned pointer is when another function is invoked, the memory occupied by subTxt_ is going to get overwritten with the stack variables of the next function invoked.
Better:
char* subTxt(char* text, int index, int len)
{
char *subTxt = new char[1000];
...
return subTxt_;
}
And then make sure whoever invokes subTxt remembers to delete [] on the returned pointer.
Or just use std::string and be done with it (unless this is an academic exercise).
Also, this is undefined behavior:
for (int t = 0; t < textLen; t++)
{
if (text[t] == separator[0] && text[t + 1] == separator[1] && text[t + 2] == separator[2])
when t == textLen-1, then referencing text[t+2] and text[t+1] is an out of bounds access. Change it to be:
for (int t = 2; t < textLen; t++)
{
if (text[t-2] == separator[0] && text[t -1] == separator[1] && text[t] == separator[2])
And do similar fixups with t within the block as well.
Well you can create a splitstring function instead of a struct/class.
Anyway your code still looks quite "C" like with its fixed size char arrays. This will limit the usability and stability (out-of-bound array bugs).
Strings in C++ are usually of type std::string.
and then C++ has string_view to make views on that string (so no data gets copied, but it also means your string_view is only valid for as long as the string it is viewing lives).
If you don't know the number of substrings in a string up-front, you should not use a fixed size array, but a std::vector (which can resize internally if needed)
This is what a split_string function would look like in current C++, note that the code also shows better what it is doing compared to "C" style programming that show more what you are doing.
std::vector<std::string_view> split_string(std::string_view string, std::string_view delimiters)
{
std::vector<std::string_view> substrings;
if(delimiters.size() == 0ul)
{
substrings.emplace_back(string);
return substrings;
}
auto start_pos = string.find_first_not_of(delimiters);
auto end_pos = start_pos;
auto max_length = string.length();
while(start_pos < max_length)
{
end_pos = std::min(max_length, string.find_first_of(delimiters, start_pos));
if(end_pos != start_pos)
{
substrings.emplace_back(&string[start_pos], end_pos - start_pos);
start_pos = string.find_first_not_of(delimiters, end_pos);
}
}
return substrings;
}
Take a look at std::string_view.
You can avoid allocating memory and it has a built-in substring function.
Just be careful when using printf for printing to console as "%s" will
print the whole string.
See printf documentation.
for(auto view : container_with_string_views)
printf("%.*s, (int)view.size(), view.data());
I am writing a function CreateGrid() that is trying to take a std::string and a 2d std::array as parameters, and put the individual characters from the std::string into the array. The rest of the array, if space is left, should be filled with the alphabetical characters A-Y, inclusive, in alphabetical order, providing they do not already appear in the std::string. Each character should only appear once in the final returned array.
So for input string keyword = "HELO";
The output would be:
H E L
O A B
C D F
Note the char 'E' only appears once.
I am trying to use std::find() to test whether all the chars in the alphabet A-Y (Z intentionally excluded) is already in the array, due to the keyword, before inserting it if it is not so that there are no duplicates. I am getting a compile error.
Code:
array<array<char,3>,3> CreateGrid(std::string keyword, array<array<char,3>,3> myArray)
{
char letterToFind = 'A';
for (int row = (keywordLength/3); row < 3; row++ )
{
for (int column = (keywordLength % 3); column < 3; column++)
{
auto it = std::find(begin(myArray), end(myArray), letterToFind);
if ( it == end(myArray) ) // value not in array
{
myArray[row][column] = letterToFind; //insert
}
letterToFind++;
}
}
return myArray;
}
int main()
{
array<array<char,3>,3> myArray = { {'H','E','L'}, {'O','+','+'}, {'+','+','+'} };
CreateGrid("HELO", myArray);
return 0;
}
I get a compile error for this line:
auto it = std::find(begin(myArray), end(myArray), letterToFind);
message : see reference to function template instantiation '_InIt std::find<std::_Array_iterator<_Ty,5>,char>(_InIt,const _InIt,const char &)' being compiled with[_InIt=std::_Array_iterator<std::array<char,3>3>,_Ty=std::array<char,3>]
How do I check to see if a char is in the array already, and if not then add it?
This is not normally trivial since you have nested arrays. std::find can only return an iterator to the outer array, which isn't useful if you need to change the value in the inner array.
However, I notice that you don't actually use it other than to see if the sought element was located. So, we can redefine the operation: instead of finding the element in an inner array that contains the value, it's sufficient to find any inner array that contains the value you're looking for:
auto it = std::find(
begin(myArray), end(myArray),
[letterToFind](array<char,3> const & inner) {
return std::find(begin(inner), end(inner), letterToFind) != end(inner);
}
);
If you found such an inner array, then you know that the value exists in the 2d array and can proceed.
Since you don't need the iterator, you could also use std::any_of instead:
bool found = std::any_of(
begin(myArray), end(myArray),
[letterToFind](array<char,3> const & inner) {
return std::find(begin(inner), end(inner), letterToFind) != end(inner);
}
);
Your myArray parameter is an array containing array<char,3> elements. You are using find() to search only that outer array. So begin(myArray) will return an iterator that enumerates array<char,3> elements, and you can't compare a single char to a whole array<char,3>, which is why your find() call does not compile. You would have to loop though the outer array calling find() on each inner array instead.
A simpler way to implement this is to use a lookup table to keep track of the characters that you have already seen, eg:
const size_t MaxRows = 3;
const size_t MaxColumns = 3;
const size_t MaxCells = MaxRows * MaxColumns;
using gridRow = std::array<char, MaxColumns>;
using grid = std::array<gridRow, MaxRows>;
grid CreateGrid(const std::string &keyword)
{
grid g;
std::array<bool, 256> lookup{};
size_t numFilled = 0;
for(size_t i = 0; (i < keyword.size()) && (numFilled < MaxCells); ++i)
{
if (!lookup[static_cast<unsigned char>(keyword[i])])
{
lookup[static_cast<unsigned char>(keyword[i])] = true;
g[numFilled / 3][numFilled % 3] = keyword[i];
++numFilled;
}
}
for(char ch = 'A'; (ch <= 'Y') && (numFilled < MaxCells); ++ch)
{
if (!lookup[static_cast<unsigned char>(ch)])
{
g[numFilled / 3][numFilled % 3] = ch;
++numFilled;
}
}
return g;
}
int main()
{
grid myArray = CreateGrid("HELO");
...
return 0;
}
Live Demo
Alternatively, you can use a std::set or std::unordered_set for the lookup:
#include <unordered_set>
const size_t MaxRows = 3;
const size_t MaxColumns = 3;
const size_t MaxCells = MaxRows * MaxColumns;
using gridRow = std::array<char, MaxColumns>;
using grid = std::array<gridRow, MaxRows>;
grid CreateGrid(const std::string &keyword)
{
grid g;
std::unordered_set<char> lookup;
size_t numFilled = 0;
for(size_t i = 0; (i < keyword.size()) && (numFilled < MaxCells); ++i)
{
if (lookup.insert(keyword[i]).second)
{
g[numFilled / 3][numFilled % 3] = keyword[i];
++numFilled;
}
}
for(char ch = 'A'; (ch <= 'Y') && (numFilled < MaxCells); ++ch)
{
if (lookup.insert(ch).second)
{
g[numFilled / 3][numFilled % 3] = ch;
++numFilled;
}
}
return g;
}
int main()
{
grid myArray = CreateGrid("HELO");
...
return 0;
}
Live Demo
I edited the code. But now it's showing runtime error. Can anyone tell why ? This is a program to sum 2 arrays and display output in third array.
I also wanted to know if this code could be optimized ?
void sumOfTwoArrays(int arr[], int size1, int brr[], int size2, int crr[])
{
int k;
if(size1>size2){
k = size1;
}
else
k = size2;
int c = k;
int r = 0;
int i = size1-1;
int j = size2-1;
for(;i>=0&&j>=0;i--,j--){
int n = arr[i] + brr[j] + r;
if(n<=9){
crr[c] = n;
}
else
{
int r = n/10;
n = n%10;
crr[c] = n;
}
c--;
}
while(arr[i]>=0){
crr[c] = arr[i] + r;
r = 0;
c--;
}
while(brr[j]>=0){
crr[c] = brr[j] + r;
r = 0;
c--;
}
if(r!=0){
crr[c] = r;
}
}
You declare variables in a block scope, i.e. inside { ... }, and these variables are visible only within this block:
if(size1>size2){
int crr[size1+1];
int c = size1;
}
else{
int crr[size2+1];
int c = size2;
}
...
crr[c] = ... // neither crr nor c are valid here any more
BTW: C++ does not support variable length arrays like int crr[size1+1] (when size is not a compile-time-constant).
To overcome this, write...
int *crr;
int c;
if(size1>size2){
crr = new int[size1+1];
c = size1;
}
else{
crr = new int[size2+1];
c = size2;
}
...
delete[] crr;
About scope issue: see Stephan's answer.
I also wanted to know if this code could be optimized
By use of std::vector. OK, the following is only a fine option if you can use vectors outside as well – copying the raw arrays into vectors wouldn't be efficient either... But if you can, then you might like this variant:
template <typename T> // optional: you're more flexible if you make a template of...
void sumOfTwoArrays(std::vector<T> const& va, std::vector<T> const& vb, std::vector<T>& vr)
{
vr.resize(std::max(va.size(), vb.size() + 1));
int carry = 0; // renamed r to something more meaningful
// these pairs will help to avoid code duplication later
std::pair pa(va, va.rbegin());
std::pair pb(vb, vb.rbegin());
auto ir = vr.rbegin();
while(pa.second != pa.first.rend() && pb.second != pb.first.rend())
{
// just skip the if/else:
// assume you have arbitrary number, the else case will be entered anyway
// in 50 % of the cases - in the other 50 %, the else branch calculates
// the correct result, too; and on most modern machines, the branch is
// rather expensive, so you result in easier code and have quite a good
// chance to even perform better...
carry += *pa.second + *pb.second;
*ir = carry % 10;
carry /= 10;
++ir, ++pa.second, ++pb.second;
}
// avoiding of two identical while loops: iterate over the two pairs...
for(auto p : { pa, pb })
{
// just loop over, if we are already at the end, won't enter...
while(p.second != p.first.rend())
{
// STILL need to continue calculating the carry!
// imagine we have set it and ciphers following are all 9!
carry += *p.second;
*ir = carry % 10;
carry /= 10;
++ir, ++p.second;
}
}
// assign either 0 or 1...
*ir = carry;
}
Variant: instead of assigning 0, you could erase first element at the very end:
if(carry == 0)
{
vr.erase(vr.begin());
}
else
{
*ir = carry;
}
Note that this will move all the elements one position to front. On the other hand, if you repeatedly add vectors already containing a leading zero, you might prepend another one again and again without need, if you don't drop it again.
You wouldn't experience any of these issues if you inverted the order of digits in the vector, having least significant one at position 0 (you'd exchange rbegin() and rend() with begin() and end(), but would use the former for printing data to display...). Erasure at the end would be an O(1) operation then:
if(carry == 0)
{
vr.erase(std::previous(vr.end())
}
// ...
All this above will only work as expected if you keep your vectors normalised (i. e. all digits in between 0 and 9 inclusive). You might consider packing the vector into a separate class such that the data is hidden away from the user and only can be modified in controlled manner (assume you have a fine vector, but a user does v[7] = -1012...).
A runtime error suggests that it is a memory issue i.e. you are writing to some memory which is not allocated to be used by your code. So, as mentioned by other contributors, you should allocate proper memory for your arrays.
Following is modified version of your code which is working fine. You can see it working here:
void sumOfTwoArrays(int arr1[], int size1, int arr2[], int size2, int sumArr[])
{
int maxLen;
int* tArry;
int l;
if(size1>size2) { maxLen = size1; tArry = arr1; l = size1 - size2; }
else { maxLen = size2; tArry = arr2; l = size2 - size1; }
int carry = 0;
while(size1 && size2){
carry += arr1[--size1] + arr2[--size2];
sumArr[maxLen--] = carry%10;
carry /= 10;
}
while(l){
carry += tArry[--l];
sumArr[maxLen--] = carry%10;
carry /= 10;
}
sumArr[maxLen] = carry;
}
Calling code looks something like this:
...
int a[] = {9,9,9,9,9};
int b[] = {1};
int l1 = sizeof(a) / sizeof(int), l2 = sizeof(b)/sizeof(int);
int l3 = ((l1 > l2) ? l1 : l2) + 1;
int *c = new int[l3];
sumOfTwoArrays(a, l1, b, l2, c);
...
delete [] c;
...
Written code to find and remove the largest word in a string without the using of library functions. Everything works fine. But when I want to free memory, the result is negative (displays an empty line). If you remove the call to the memory release function, everything will work correctly, but there will be a leak of memory.
How do I fix it? Please help me.
#include <iostream>
using namespace std;
int length(char *text) // string length
{
char *begin = text;
while(*text++);
return text - begin - 1;
}
int size(char **text) // size of two-dimensional array
{
int i = 0;
while(text[i]) i++;
return i;
}
void free_memory(char **text)
{
for(int i=0; i<size(text); i++)
delete text[i];
delete [] text;
}
char **split(char *text, char delim)
{
int words = 1;
int len = length(text);
for(int i=0; i<len; i++)
if(text[i] == delim) words++;
char **result = new char*[words + 1];
int j = 0, t = 0;
for(int i=0; i<words; i++)
{
result[i] = new char[len];
while(text[j] != delim && text[j] != '\0') result[i][t++] = text[j++];
j++;
t = 0;
}
result[words + 1] = nullptr;
return result;
}
char *strcat(char *source, char *destination)
{
char *begin = destination;
while(*destination) destination++;
*destination++ = ' ';
while(*source) *destination++ = *source++;
return begin;
}
char *removeWord(char *in_string)
{
char **words = split(in_string, ' ');
int max = length(words[0]);
int j = 0;
for(int i=0; i<size(words); i++)
if(max < length(words[i]))
{
max = length(words[i]);
j = i;
}
int index;
char *result;
if(!j) index = 1;
else index = 0;
result = words[index];
for(int i=0; i<size(words); i++)
if(i != j && i != index)
result = strcat(words[i], result);
free_memory(words); // I want free memory here
return result;
}
int main()
{
char text[] = "audi and volkswagen are the best car";
cout << removeWord(text) << endl;
return 0;
}
In fact, this is C style programming - not C++. I see that your aim is to implement everything from scratch, possibly for practicing. But even then, your code is not designed/structured properly.
Besides that, you also have several bugs in your code:
result[words + 1] = nullptr; must be result[words] = nullptr;
You need result[i][t] = '\0'; after the while loop in split
delete text[i] must be delete [] text[i]
You cannot assign to your result pointer memory from words, then free it and then return it for use by the caller.
There is at least one further bug in the second half of removeWord. It would be tedious to try to understand what you are trying to do there.
You might want to start with a simpler task. You also should proceed step-by-step and check each function for correctness independently first and not implement everything and then test. Also take a look at the tool valgrind for memory checking - if you use Linux.
The way you free memory correctly is to use RAII:
Only use new and new[] in constructors
Pair those with delete and delete[] in the corresponding destructor
Use automatic storage duration objects as much as possible
If you are specifically not using std::string and std::vector etc, for reasons of learning pointers, you will end up writing some small number of classes that resemble string and vector and unique_ptr, and then you go about programming as if you were using the std versions.
You have two issues. First is that result is assigned to a memory location in words. Second, is that you're storing the result of strcat in words[i] which will likely not have enough room (see strcat documentation).
result = new char[len(in_string)+1]; // +1 for space for null char
// the old loop reversed the word order -- if you want to keep doing
// that, make this a descending loop
for(int i=0; i<size(words); i++)
if(i != j && i != index)
strcat(result, words[i]);
free_memory(words);
return result;
So that when you free words, what result points to is also free'd. You would then need to free your result in main().
int main()
{
char text[] = "audi and volkswagen are the best car";
char * result = removeWord(text);
cout << result << endl;
delete[] result;
return 0;
}
I'm trying to copy data from an array of character that send from main to another one in my local function and I always see garbage characters even though I've add '\0' at the end of the string.
Here is my partial of the code.
for (int i = 0; i < strlen(main) ; i++){
if (main[i] != ';'){
local[i] = main[i]; // Copy the characters until `;` isn't found
} else {
local[i] = '\0' ; // If `;` found, null terminate the copied destination.
break;
}
}
so basically the data that being send from main for example like this
look;can;you;see;me
My Local-----> 'look??y??>c?Lw?T?w??>c?2+a?'
Actual data in main---> 'look'
As you can see from the above example I'm trying to get only the first word and I always get garbage I don't know why?
EDIT:
This is the almost the whole function which 100% sure that is causing me the problem.
void myFunction(char main[ ]){
for (int i = 0; i < strlen(main) ; i++){
if (main[i] != ';'){
local[i] = main[i]; // Copy the characters until `;` isn't found
} else {
local[i] = '\0' ; // If `;` found, null terminate the copied destination.
break;
}
}
if(main[i] != '\0'){
int col = 0, row = 0;
do {
if(main[i] == ';' || main[i] == '\0') {
sending[row++][col] = '\0';
col = 0;
} else {
sending[row][col++] = main[i];
}
} while(main[i++] != '\0');
}
}
You are forgetting to take care of zero terminating the string if the ; is not found. A simple fix is tweaking your for loop so it also sees the \0 in main:
for (int i = 0; i <= strlen(main); i++) {
The standard library handles this for you. Using strchr and strncpy:
size_t length = std::strlen(main);
const char* current_pos = main;
for (int i = 0; ; ++i) {
size_t chars_remaining = length - std::distance(main, current_pos);
const char* end_of_field = std::strchr(current_pos, ';');
if (end_of_field == NULL) {
std::strncpy(local[i], current_pos, chars_remaining + 1);
// we're at the end of the input
break;
}
else {
size_t field_length = std::distance(current_pos, end_of_field);
std::strncpy(local[i], current_pos, field_length);
// don't forget to NUL-terminate the string
local[i][field_length] = '\0';
// go to next character for the next iteration through loop
current_pos = end_of_field + 1;
}
}
Personally, I prefer std::find and std::copy (from <algorithm>):
size_t length = std::strlen(main);
const char* current_pos = main;
for (int i = 0; ; ++i) {
size_t chars_remaining = length - std::distance(main, current_pos);
const char* end_of_field = std::find(current_pos, current_pos + chars_remaining, ';');
char* output_end = std::copy(current_pos, end_of_field, local[i]);
// don't forget to NUL-terminate the string
*output_end = '\0';
// if we're at the end of main, then we're done;
// we're at the end if we're on a NUL character
if (*end_of_field == '\0')
break;
// go to next character for the next iteration through loop
current_pos = end_of_field + 1;
}
Not the prettiest code I've ever written, but that's largely due to using C-style strings and pointer arithmetic, which don't look avoidable given the original question. Additionally, I haven't put in the needed checks for overflow. It's easy enough to do that, but it's even easier to use std::vector<std::string> and have the standard library worry about that for you.