I am using strstr() function but I am getting the crash.
This part of code is crashing with error "Access violation reading location 0x0000006c."
strstr(p_czCharactersToDelete, (const char*)p_czInputString[index]))
Here is the complete code...
#include "stdafx.h"
#include <iostream>
#include <string>
void delchar(char* p_czInputString, const char* p_czCharactersToDelete)
{
for (size_t index = 0; index < strlen(p_czInputString); ++index)
{
if(NULL != strstr(p_czCharactersToDelete, (const char*)p_czInputString[index]))
{
printf_s("%c",p_czInputString[index]);
}
}
}
int main(int argc, char* argv[])
{
char c[32];
strncpy_s(c, "life of pie", 32);
delchar(c, "def");
// will output 'li o pi'
std::cout << c << std::endl;
}
The prototype of strstr() is as follows,
char * strstr ( char * str1, const char * str2 );
The function is used to locate substring from a main string. It returns a pointer to the first occurrence of str2 in str1, or a null pointer if str2 is not part of str1.
In your case you are passing the wrong parameters to the strstr(). You are calling,
strstr(p_czCharactersToDelete, (const char*)p_czInputString[index]));, which is wrong. Because the pointer p_czCharactersToDelete points to the sub string constant and p_czInputString points to the main string. Call strstr() as strstr(p_czInputString, p_czCharactersToDelete); and make corresponding changes in the function delchar().
you are using the wrong strstr.
probably you need strchr or strpbrk.
#include <cstring>
#include <algorithm>
class Include {
public:
Include(const char *list){ m_list = list; }
bool operator()(char ch) const
{
return ( strchr(m_list, ch) != NULL );
}
private:
const char *m_list;
};
void delchar(char* p_czInputString, const char* p_czCharactersToDelete){
Include inc(p_czCharactersToDelete);
char *last = std::remove_if(p_czInputString, p_czInputString + strlen(p_czInputString), inc);
*last = '\0';
}
Related
I'm a newbie in C++ learning the language and playing around. I wrote a piece of code which behavior I don't understand. Could someone explain why the code below prints out random junk and not the first character of the first string in the list (that is a).
#include <iostream>
#include <vector>
#include <string>
#include <cstdlib>
#include <ctime>
#include <climits>
#include <stdio.h>
char* str2char(std::string str)
{
char cset[str.size()+1]; // +1 for the null character
for(int i = 0; i < str.size(); i++)
{
cset[i] = str[i];
}
cset[str.size()] = '\0';
return cset;
}
int main (int argc, char * const argv[]) {
std::vector< std::string > ladontakadet;
ladontakadet.push_back("aabcbbca");
ladontakadet.push_back("abcdabcd");
ladontakadet.push_back("cbbdcdaa");
ladontakadet.push_back("aadcbdca");
ladontakadet.push_back("cccbaaab");
ladontakadet.push_back("dabccbaa");
ladontakadet.push_back("ccbdcbad");
ladontakadet.push_back("bdcbccad");
ladontakadet.push_back("ddcadccb");
ladontakadet.push_back("baccddaa");
std::string v = ladontakadet.at(0);
char *r;
r = str2char(v);
std::cout << r[0] << std::endl;
return 0;
}
Why is my returning garbage, when I'm expecting it to output a?
Thnx for any help!
P.S. The output of this code is random. It doesn't always print the same character..:S
It's because you return a pointer to a local variable, a local variable that goes out of scope when the function returns.
You are already using std::string for the argument, use it instead of the array and the return pointer.
If your aim is to pass the content of a std::string to a function modifying the content of a char*:
#include <iostream>
#include <vector>
void f(char* s) {
s[0] = 'H';
}
std::vector<char> to_vector(const std::string& s) {
return std::vector<char>(s.c_str(), s.c_str() + s.size() + 1);
}
int main(void)
{
std::string s = "_ello";
std::vector<char> t = to_vector(s);
f(t.data());
std::cout << t.data() << std::endl;
}
Your function is returning garbage because you're returning the address of a local variable which goes out of scope after your function returns. It should probably look like this:
char* str2char(const std::string &str)
{
char *const cset = new char[str.size() + 1]; // +1 for the null character
strcpy(cset, str.c_str());
return cset;
}
You will need to delete your variable r by doing delete[] r;. Ideally though you wouldn't be using raw pointers, and you would use std::string for everything, or wrap the char * in a std::unique_ptr.
I've written a simple function to count occurrences of a character in a string. The compiler is fine. However, as I try to run it, it produced a segmentation fault.
#include <iostream>
using namespace std;
// To count the number of occurences of x in p
// p is a ะก-style null-terminated string
int count_x(char* p, char x)
{
if (p == nullptr)
{
return 0;
}
// start the counter
int count = 0;
while (p != nullptr)
{
if (*p == x)
{
++count;
}
}
return count;
}
int main(int argc, char const *argv[])
{
char myString[] = "Hello";
cout << count_x(myString, 'l');
return 0;
}
There's two mistakes in your code:
You only ever look at the first character in the string.
The last character of a null terminated string is a null character. You're testing the pointer itself.
You need to use std::string
#include <string>
#include <algorithm>
#include <iostream>
int main()
{
std::string str = "Hello";
std::cout << std::count(str.begin(), str.end(), 'l');
}
I am writing a command shell in C++ using the POSIX api, and have hit a snag. I am executing via execvp(3), so I somehow need to turn the std::string that contains the command into a suitable array of char* consts*'s that can be passed to:
int execvp(const char *file, char *const argv[]);
I have been racking my brain for hours but I can't think of any realistic or sane way to do this. Any help or insight on how I can achieve this conversion would be greatly appreciated. Thank you and have a good day!
edit:
As per request of Chnossos, here is an example:
const char *args[] = {"echo", "Hello,", "world!"};
execvp(args[0], args);
Assuming you have a string that contains more than "one argument", you will first have to split the string (using a std::vector<std::string> would work to store the separate strings), then for each element in the vector, store the .c_str() of that string into a const char args[MAXARGS] [or a std::vector<const char*> args; and use args.data() if you don't mind using C++11]. Do not forget to store a 0 or nullptr in the last element.
It is critical if you use c_str that the string you are basing that of is not a temporary: const char* x = str.substr(11, 33).c_str(); will not give you the thing you want, because at the end of that line, the temporary string is destroyed, and its storage freed.
If you have only one actual argument,
const char* args[2] = { str.c_str(), 0 };
would work.
Examplary approach:
#include <string>
#include <vector>
#include <cstring>
using namespace std;
int execvp(const char *file, char *const argv[]) {
//doing sth
}
int main() {
string s = "echo Hello world!";
char* cs = strdup(s.c_str());
char* lastbeg = cs;
vector<char *> collection;
for (char *itcs = cs; *itcs; itcs++) {
if (*itcs == ' ') {
*itcs = 0;
collection.push_back(lastbeg);
lastbeg = itcs + 1;
}
}
collection.push_back(lastbeg);
for (auto x: collection) {
printf("%s\n", x);
}
execvp("abc.txt", &collection[0]);
}
Notice that the memory for the cs isn't freed here... in your application you would need to take care of that...
The number of elements in array can be simply extracted from collection.size()
I use this:
command_line.hpp:
#pragma once
#include <vector>
#include <string>
namespace wpsc { namespace unittest { namespace mock {
class command_line final
{
public:
explicit command_line(std::vector<std::string> args = {});
explicit command_line(int argc, char const * const * const argv);
int argc() const;
/// #remark altering memory returned by this function results in UB
char** argv() const;
std::string string() const;
private:
std::vector<std::string> args_;
mutable std::vector<char*> c_args_;
};
}}} // wpsc::unittest::mock
command_line.cpp:
#include <wpsc/unittest/mock/command_line.hpp>
#include <algorithm>
#include <sstream>
namespace wpsc { namespace unittest { namespace mock {
command_line::command_line(std::vector<std::string> args)
: args_( std::move(args) ), c_args_( )
{
}
command_line::command_line(int argc, char const * const * const argv)
: command_line{ std::vector<std::string>{ argv, argv + argc } }
{
}
int command_line::argc() const
{
return static_cast<int>(args_.size());
}
char ** command_line::argv() const
{
if(args_.empty())
return nullptr;
if(c_args_.size() != args_.size() + 1)
{
c_args_.clear();
using namespace std;
transform(begin(args_), end(args_), back_inserter(c_args_),
[](const std::string& s) { return const_cast<char*>(s.c_str()); }
);
c_args_.push_back(nullptr);
}
return c_args_.data();
}
std::string command_line::string() const
{
using namespace std;
ostringstream buffer;
copy(begin(args_), end(args_), ostream_iterator<std::string>{ buffer, " " });
return buffer.str();
}
}}} // wpsc::unittest::mock
Client code:
int main(int argc, char** argv)
{
wpsc::unittest::mock::command_line cmd1{ argc, argv };
// wpsc::unittest::mock::command_line cmd2{ {"app.exe" "-h"} };
some_app_controller c;
return c.run(cmd1.argc(), cmd1.argv());
}
If the parsing can actually be really complicated, I'd go with something like that:
std::string cmd = "some really complicated command here";
char * const args[] =
{
"sh",
"-c",
cmd.c_str(),
(char *) NULL
};
execvp(args[0], args);
So the problem is the splitting of the line into individual arguments, and filling the argument vector with the respective pointers?
Assuming you want to split at the whitespace in the line, you replace whitespace in the string with null-bytes (in-place). You can then fill the argument vector with pointers into the string.
You will have to write a single loop to go through the string.
You need to decide what the rules will be for your shell and implement them. That's a significant fraction of the work of making a shell.
You need to write this code, and it's not simple. In a typical shell, echo "Hello world!" has to become { echo, Hello world! }, while echo \"Hello world!\" has to become { echo, "Hello world!" }. And so on.
What will " do in your shell? What will ' do? You need to make these decision before you code this part.
EXC_BAD_ACCESS occurred in *str++ = *end;. What's wrong with this?
#include <iostream>
using namespace std;
int main() {
char *hello = "abcdefgh";
char c = 'c';
char *str = hello;
//printf("%s",str);
char * end = str;
char tmp;
if (str) {
while (*end) {
++end;
}
--end;
while (str < end) {
tmp = *str;
printf("hello:%s str:%c, end:%c\n", hello, *str, *end);
*str++ = *end;
*end-- = tmp;
}
}
return 0;
}
It is undefined behavior to attempt to alter a string literal. Change your code to the equivalent below, and you will see the issue:
const char *hello = "abcdefgh";
const char *str = hello;
const char * end = str;
So do you see why the line *str++ = *end; had a problem? You're attempting to write to a const area, and you can't do that.
If you want an even simpler example:
int main()
{
char *str = "abc";
str[0] = 'x';
}
Don't be surprised if this simple program produces a crash or segmentation fault when the
str[0] = 'x';
line is executed.
Unfortunately, string-literals did not have to be declared as const char* in C, and C++ brought this syntax over. So even though it looks like you are not using const, you are.
If you want the code to actually work, declare a writeable buffer, i.e. an array of char:
char hello[] = "abcdefgh";
char str[100];
strcpy(str, hello);
char end[100];
strcpy(end, str);
It seems like you're trying to reverse the string. It also looks like you're overcomplicating things.
C-style strings declared on the stack have to be declared as const char *, which means you can't change the characters as they are constant.
In C++ we use strings, and string iterators:
#include <iostream>
#include <string>
using std::string;
using std::reverse;
using std::swap;
using std::cout;
using std::endl;
int main(int argc, const char * argv[])
{
string hello("abcdefgh");
reverse(hello.begin(), hello.end());
cout << hello << endl;
return 0;
}
Manually:
static void reverse(std::string & str)
{
string::size_type b = 0, e = str.length() - 1, c = e / 2;
while(b <= c)
{
swap(str[b++], str[e--]);
}
}
Recursively:
static void reverse_helper(std::string & str,
string::size_type b,
string::size_type e)
{
if(b >= e)
return;
swap(str[b], str[e]);
reverse_helper(str, ++b, --e);
}
static void reverse(std::string & str)
{
reverse_helper(str, 0, str.length() - 1);
}
I have written the following function to replace substrings in a char. This way involves converting to a std::string then converting back to a const char. Is this the most efficient way or could I do it without this conversion or even a better way?!
const char* replaceInString(const char* find, const char* str, const char* replace)
{
std::string const text(str);
std::regex const reg(find);
std::string const newStr = std::regex_replace(text, reg, replace);
//Convert back to char
char *newChar = new char[newStr.size() + 1];
std::copy(newStr.begin(), newStr.end(), newChar);
newChar[newStr.size()] = '\0'; // terminating 0
return newChar;
}
const char* find = "hello";
const char* replace = "goodbye";
const char* oldStr = "hello james";
const char* newStr = m->replaceInString(find, oldStr, replace);
Assuming that you want a function to be called from a .c file you could use strdup (see code below).
#include <string>
#include <regex>
#include <cstdio>
#include <cstdlib>
char* replaceInString(char const *find, char const *str, char const *replace)
{
return strdup(std::regex_replace(std::string(str), std::regex(find), replace).c_str());
}
int main()
{
char *newStr = replaceInString("hello", "hello james", "goodbye");
printf("newStr = %s\n", newStr);
free(newStr);
return 0;
}
Note however that you have to free the returned memory after you're done.
Otherwise, as #jerry-coffin suggested go all the way with std::string (see code below):
#include <string>
#include <regex>
#include <iostream>
std::string replaceInString(std::string const &find, std::string const &str, std::string const &replace)
{
return std::regex_replace(std::string(str), std::regex(find), replace);
}
int main()
{
std::string str = replaceInString(std::string("hello"), std::string("hello james"), std::string("goodbye"));
std::cout << str << std::endl;
return 0;
}