Garbage characters being store in the array - c++

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.

Related

c++ Split char array without use of any library

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());

Trying to copy a char* to another char*

I have a problem that my code
char* strdup(const char* s)
{
int n = 0;
for(; *s != 0; s++)
{
n++;
}
char* p = new char[n+1];
for(int i = 0; i < n; i++)
{
p[i] = s[i];
}
p[n] = 0;
return p;
}
int main()
{
const char* p = "testing";
char* p_copy = strdup(p);
std::cout << p << '\n' << p_copy << std::endl;
return 0;
}
doesn't work as intended.
I want to write a function which takes in const char* and copies it to a new allocated char memory. When it is done it should return a pointer to the char.
Now when I try it out my output is simply:
testing
thanks for any help in advance
Try not incrementing s before you start copying it to p. I notice that in your first for loop you increment s until it points at a null, and then later use that pointer value to start your string copy. No wonder you are getting a null string.
Here:
for(; *s != 0; s++)
You increment s. So it no longer points to the beginning of the input string. It points to the null terminator of the string. Then, here:
for(int i = 0; i < n; i++)
{
p[i] = s[i];
You try to copy n characters starting from the null terminator, and you end up reading past the end of the array which has undefined behaviour.
Solution: Make a copy of s for counting the characters:
const char* s2 = s;
for(; *s2 != 0; s2++)
Even better, you could refactor the length counting part into a reusable function called strlen.

C++. How can I free memory correctly?

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;
}

c++ shift array elements to left

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)

C++ How to remove double quotes in char

I want to remove double-quotes from a string, for example 13.3" Rentina becomes 13.3 Rentina
const char* s = sheet->readStr(row, col);
int ii = strlen(s);
char* b;
b=(char*)s;
char ch;
for (int i = 0; i < ii ;++i) {
strncpy(&ch, b+ii, 1);
if(ch == '\"'){
ch = '\"';
memcpy(b+i, &ch, 1);
}
}
myfile << b;
If you deal with strings in C++, you should use character arrays and functions like strncpy only when you have a strong reason to use them. By default you should use standard string, which makes e.g. memory management much easier. The solution to your problem with std::string is
std::string s = sheet->readStr(row, col);
size_t pos = 0;
while ((pos = s.find('"', pos)) != std::string::npos)
s = s.erase(pos, 1);
myfile << s;
You cannot do b=(char*)s!!!
The compiler lets you in on this one, but you will get a runtime exception as soon as you attempt to write into the memory address space pointed by b.
The variable s is possibly pointing to an address in the code-section, which is a read-only memory address space within your program ("possibly", because perhaps that const declaration of s is just something you added on your own initiative).
You should allocate a new char array, and copy the output string into that array instead.
So first of all, change the above statement to b = (char*)malloc(strlen(s)).
In addition, do not pass to strncpy (or any other str function for that matter) an address of a char variable. These functions operate on char arrays, and either assume that the array ends with a 0 character, or set the character at the end of the array to 0.
You can try the following piece of code (assuming that your purpose is to remove the '"'):
const char* s = sheet->readStr(row, col);
int ii = strlen(s);
char* b = (char*)malloc(ii+1);
if (b != NULL)
{
int i,j;
for(i=0,j=0; i<ii; i++)
{
if (s[i] != '"')
b[j++] = s[i];
}
b[j] = 0;
// Add your code here (do whatever you wanna do with 'b')
free(b);
}
else
{
printf("Out of memory\n");
}