C++ char** -> vector<string> -> string -> char** parsing problem - c++

Lets say that I'm trying to solve a parsing problem of string to char **
For some reason the below code generates a lot of trash, can anyone have a look at it please?
Here's what it's supposed to do :
Dump all argv into a string_array
container
Dump everything in the string_array
container into a std::string and
separate with spaces
Break the string down into string
tokens using boost/algorithm/string
create a new char ** and dump all
tokens into it, print out the new char **, clean up
What have I done wrong ?
#include <string>
#include <vector>
#include <iostream>
#include <boost/algorithm/string.hpp>
using namespace std;
using namespace boost;
typedef vector<string> string_array;
int main(int argc, char ** argv)
{
string_array args;
string_array tokens;
cout << "Real arguments :" << endl;
for(int i = 0; i < argc; i++)
{ cout << argv[i] << endl;}
string arg = "";
for(int i = 1; i < argc; i++)
{
args.push_back(argv[i]);
}
for(int i = 0; i < (int)args.size(); i++)
{
arg += args[i];
if(i != (int)args.size() - 1)
arg += " ";
}
split(tokens, arg, is_any_of(" "));
char ** new_args = NULL;
new_args = new char*[(int)tokens.size()];
for(int i = 0; i < (int)tokens.size(); i++)
{
new_args[i] = new char[(int)tokens[i].size()];
for(int j = 0; j < (int)tokens[i].size(); j++)
{
new_args[i][j] = tokens[i][j];
}
}
for(int i = 0; i < (int)tokens.size(); i++)
{ std::cout << new_args[i] << std::endl; }
delete [] new_args;
}

C-style strings (char*) are meant to be zero-terminated. So instead of new char[tokens[i].size()], you need to add 1 to the allocation: new char[token[i].size() + 1]. Also, you need to set new_args[i][tokens[i].size()] = 0 to zero-terminate the string.
Without the zero-terminator, programs would not know when to stop printing, as char* does not hold a string length, unlike std::string.

Related

c++ deleting char pointer allocated with new

In this code I am getting numbers from a file, when the first number is the size of the 2D array.
In my code I'm defining
char *filename=new char;
(I have to use char *filename, this is the exercise..)
Everything works fine, until the moment I try to delete. both delete and delete[] gives me error and crashing my program.
This is my full code:
#include <iostream>
#include <fstream>
using namespace std;
double **readmat(char *filename, int *size)/////question 2
{
ifstream read(filename);
cout << filename << endl;
if (!read)
{
cout << "Can't open file!" << endl;
exit(1);
}
read >> *size;
double **mat = new double*[*size];
for (int i = 0; i < *size; i++)
{
mat[i] = new double[*size];
for (int j = 0; j < *size; j++)
{
read >> mat[i][j];
}
}
read.close();
return mat;
}
int main()
{
int size;
char *filename = new char;
filename = "text.txt";
double **arr = readmat(filename, &size);
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
{
cout << arr[i][j]<<" , ";
}
cout << endl;
}
cout << endl;
delete filename; //<-------- this crashed my code
for (int i = 0; i < size; i++)
{
delete[] arr[i];
}
delete[] arr;
return 0;
}
This is how my file looks:
This is what the console app looks like after running the code:
Which is what I am expecting to get, but I get this error:
Does anyone have any idea what could this happen, and what I can do to fix it?
You are trying to delete a char* that is not pointing at memory allocated with new.
On this line:
char *filename = new char;
You do new some memory (a single char, not a string of chars). But then on this line:
filename = "text.txt";
You change the char* pointer to point at completely different memory, thus leaking the memory you new'ed.
Then on this line:
delete filename;
You try to delete the "text.txt" literal, not the char you new'ed. That is why you crash.
For what you are attempting to do, you need to do this instead:
char *filename = new char[strlen("text.txt")+1];
strcpy(filename, "text.txt");
...
delete[] filename;
However, you really should not be using new/new[] for filename at all. Use std::string instead:
#include <fstream>
#include <string>
double **readmat(const std::string &filename, int *size)
{
std::ifstream read(filename.c_str());
...
}
int main()
{
int size;
double **arr = readmat("text.txt", &size);
...
}
Alternatively:
#include <fstream>
#include <string>
double **readmat(const char *filename, int *size)
{
ifstream read(filename);
...
}
int main()
{
int size;
std::string filename = "text.txt";
double **arr = readmat(filename.c_str(), &size);
// or simply:
// double **arr = readmat("text.txt", &size);
...
}
And then, while you are at it, you should not be using new[] for your matrix, either. Use std::vector instead:
#include <vector>
std::vector< std::vector<double> > readmat(char *filename)
{
...
int size;
read >> size;
std::vector< std::vector<double> > mat(size);
for (int i = 0; i < size; i++)
{
mat[i].resize(size);
for (int j = 0; j < size; j++)
{
read >> mat[i][j];
}
}
return mat;
}
int main()
{
...
std::vector< std::vector<double> > arr = readmat("text.txt");
size_t size = arr.size();
for (size_t i = 0; i < size; i++)
{
for (size_t j = 0; j < size; j++)
{
std::cout << arr[i][j] << " , ";
}
std::cout << endl;
}
std::cout << endl;
return 0;
}
char *filename = new char;
filename = "text.txt";
This creates a new char, then leaks it because the pointer filename is reassigned to something that is statically declared.
Therefore, later on you delete something else than the original char.
Multiple issues here (using new instead of new[], etc). Suggestion, forget everything and use std::string and STL.
This is the source of your problem:
char *filename = new char;
filename = "text.txt";
filename no longer points to dynamically allocated memory, thus you can't delete it (and you're also leaking 1 byte of memory). Change your declaration to const char *filename = "test.txt"; and remove the delete filename;.
new char allocates a single character on the heap. Most functions that take a const char* as parameter expect a pointer to the first element of an array with the null character (\0) as delimiter (a C-style string).
You shouldn't even be able to assign a string literal to a variable of type char *, at least not in standard C++. You also don't need to dynamically allocate memory for string literals, simply use
const char *filename = "text.txt";
Then you also don't delete pointers to string literals. (That's what causes the error most likely, you deleted a pointer that pointed to a string literal)
Just replace
char* filename = new char;
with
const char* filename = "text.txt";
and remove
delete filename;
This is how your final code will look
int main()
{
int size;
const char *filename = "text.txt";
double **arr = readmat(filename, &size);
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
{
cout << arr[i][j]<<" , ";
}
cout << endl;
}
cout << endl;
for (int i = 0; i < size; i++)
{
delete[] arr[i];
}
delete[] arr;
return 0;
}

Run-Time Check Failure #2 - s for array of C-Strings

I have the following two 2D Arrays of C-Strings. I am trying to copy the first one onto the second using strcpy() function. However, I keep getting the runtime error.
#define _CRT_SECURE_NO_WARNINGS
#include <cstring>
#include <iostream>
using namespace std;
int main() {
char word1[3][3] = { "Hello", "Bonjour", "Ni Hao" };
char word2[3][3] = { "Steve", "Pei", "Frank" };
char temp[] = "";
for (int i = 0; i < 3; i++) {
strcpy(temp, word1[i]);
strcpy(word1[i], word2[i]);
strcpy(word2[i], temp);
}
for (int i = 0; i < 3; i++) {
cout << word2[i] << " ";
}
cout << endl;
}
In your code i find several mistake.
your char array word1,word2,temp isn't initialize properly.you need to increase size of array.
in loop you use 3.it will break your output if your word's length become grater than 4.
So here i give you little solution.But its better use user input as a size of array so that any input can match properly.
#define _CRT_SECURE_NO_WARNINGS
#include <cstring>
#include <iostream>
using namespace std;
int main() {
char word1[10][10] = { "Hello", "Bonjour", "Ni Hao" };//increase array size to fit word
char word2[10][10] = { "Steve", "Pei", "Frank" };//same here
char temp[10] = "";//same here
for (int i = 0; i < 10; i++) {
strcpy(temp, word1[i]);
strcpy(word1[i], word2[i]);
strcpy(word2[i], temp);
}
for (int i = 0; i <10; i++) {
cout << word2[i] << " ";
}
cout << endl;
}

Converting vector<string> to char** results in segmentation fault

I am a absolutely begginer in C++ but i have an assignent. I have to convert a vector to char** to use it in execvp. So i wrote this test which is building ok but when i run it i get segmentation fault instead of "First". I am bad at pointer and i would like your help. Thanks
#include <iostream>
#include <vector>
#include <string>
#include <cstring>
using namespace std;
int main()
{
vector<string>* list = new vector<string>();
list->push_back("First");
list->push_back("Second");
list->push_back("Third");
char ** arr;
arr[0] = strdup(list->at(0).c_str());
cout << arr[0] << endl;
return 0;
}
EDIT 1
Ok here's the actual problem. The Command::getCommandArray() seems to work as expected but when i call it from main and try to display the arr[0] it results in segmentation fault again. Why?
// Command.cpp
char** Command::getCommandArray()
{
int i=0;
int len = args->size() + 2;
char* arr[len];
arr[0] = strdup(this->commandName->c_str());
arr[len-1] = NULL;
for (i=0; i<this->args->size(); i++)
{
arr[i+1] = strdup(this->args->at(i).c_str());
}
cout << "in: " << arr[0] << endl; // PRINTS AS EXPECTED
return arr;
}
// main.cpp
do {
char** arr = tmp->getCommandArray();
cout << arr[0] << endl; // SEGMENTATION FAULT HERE
} while((tmp = tmp->getPipeline()) != NULL);
EDIT 2 Ok i solved it. Thank you very much!
I had to change line
char* arr[len];
to
char** arr = new char*[len];
I see no reason to duplicate strings here, or to manually manage memory. You can just use another vector to store the char pointers, and get a pointer to that vector's memory.
int main()
{
std::vector<std::string> list;
list.push_back("First");
list.push_back("Second");
list.push_back("Third");
std::vector<char*> ptr_list;
for (std::size_t i = 0; i != list.size(); ++i) {
ptr_list.push_back(&list.at(i)[0]);
}
char** arr = &ptr_list[0];
std::cout << arr[0] << std::endl;
}
It should be something like:
int main()
{
std::vector<std::string> list;
list.push_back("First");
list.push_back("Second");
list.push_back("Third");
char** arr = new char*[list.size()];
for (std::size_t i = 0; i != list.size(); ++i) {
arr[i] = strdup(list.at(i).c_str());
}
std::cout << arr[0] << std::endl;
for (std::size_t i = 0; i != list.size(); ++i) {
free(arr[i]);
}
delete[] arr;
}
Note that the argv and envp arrays you pass in to execve() need to be null terminated (in addition to the strings in those arrays):
char ** convert(std::vector<std::string> v)
{
char ** t = new char* [v.size() + 1];
// Need this for execve
t[v.size()] = nullptr;
for (int i = 0 ; i < v.size(); ++i)
{
t[i] = strdup(v[i].c_str());
}
return t;
}

How to save a character into char array

So i would like to know how to save characters in a char array. something like this.
int const l=100;
char a[l];
char b[l]
cin.getline(a,l);
int d;
d=strlen (a);
int i=0;
for(i=0;i<d;i++)
{
if(a[i]=='a')
{do something so i can save only the items that match the
criteria in the new char array}
I don't know if there is a function to do this or even how i should approach it .
First of all, if you really write in C++, avoid arrays. They are tougher to handle than objects really created for array or string handling, such as std::string.
Try this one:
#include <string>
#include <iostream>
int main(int argc, char * argv[])
{
std::string s, s1;
std::getline(std::cin, s);
for (int i = 0; i < s.length(); i++)
{
if (s[i] == 'a')
s1.push_back(s[i]);
}
std::cout << "Processed string: " << s1;
}
This may help if you don't use STL:
int j = 0; // index for b. An array will be filled from the zero element
for (int i = 0; i < d; i++)
{
if (a[i] == 'a') // or any filter criter
{
b[j] = a[i];
++j;
}
}
b[j] = '\0';
With STL (and C++11):
auto it = std::copy_if(&a[0], &a[d], &b[0], [](char c){ return c == 'a'; });
*it = '\0';

Incomplete input from user

I have modified the code from my previous question, and now it looks like this:
//#include "stdafx.h"
#include <iostream>
#include <cstring>
#include <chrono>
#include <cassert>
using namespace std;
const int MAX_SIZE=10000;
const int MAX_STRINGS = 10;
char** strings=new char*[10];
int len;
char* GetLongestCommonSubstring( char* str1, char* str2 );
inline void readNumberSubstrings();
inline const char* getMaxSubstring();
void readNumberSubstrings()
{
cin >> len;
assert(len >= 1 && len <=MAX_STRINGS);
for(int i=0; i<len;i++)
strings[i]=new char[MAX_SIZE];
for(int i=0; i<len; i++)
cin >> strings[i];
}
const char* getMaxSubstring()
{
char *maxSubstring=strings[0];
auto begin = chrono::high_resolution_clock::now();
for(int i=1; i < len; i++)
maxSubstring=GetLongestCommonSubstring(maxSubstring, strings[i]);
cout << chrono::duration_cast <chrono::milliseconds> (chrono::high_resolution_clock::now()-begin).count() << endl;
return maxSubstring;
}
char* GetLongestCommonSubstring( char* string1, char* string2 )
{
if (strlen(string1)==0 || strlen(string2)==0) cerr << "error!";
int *x=new int[strlen(string2)+ 1]();
int *y= new int[strlen(string2)+ 1]();
int **previous = &x;
int **current = &y;
int max_length = 0;
int result_index = 0;
int length;
int M=strlen(string2) - 1;
for(int i = strlen(string1) - 1; i >= 0; i--)
{
for(int j = M; j >= 0; j--)
{
if(string1[i] != string2[j])
(*current)[j] = 0;
else
{
length = 1 + (*previous)[j + 1];
if (length > max_length)
{
max_length = length;
result_index = i;
}
(*current)[j] = length;
}
}
swap(previous, current);
}
delete[] x;
delete[] y;
string1[max_length+result_index]='\0';
return &(string1[result_index]);
}
int main()
{
readNumberSubstrings();
cout << getMaxSubstring() << endl;
return 0;
}
It's still solving the generalised longest common substring problem, and now it's rather fast.
But there's a catch: if a user specifies, say, 3 as a number of strings he's about to enter, and then only actually enters one string, this code waits forever.
How do I change that?
If you read from a file and the number of arguments isn't equal to the number of arguments provided, just print a nice, clean error message to the user.
"Expected 7 arguments, received 3:"
Print out the arguments you found so the user has an idea of what the program is looking at when it spits out the error.
As for human input, I agree with the comments. The program should wait until the user close it or enters all the needed arguments.