I have written a function to process a variadic input arguments like below -
std::string ReturnMessage(const char * format, ...)
{
va_list vl;
va_start(vl, format);
std::stringstream ss;
for(int i = 0; format[i] != '\0'; ++i)
{
switch(format[i])
{
case 's':
{
char *str = NULL;
str = va_arg(vl, char *);
if(*str)
{ //Getting memory access violation here
ss << str;
}
}
break;
}
}
val_end(vl);
return ss.str()
}
No when user assigns non string value(ReturnMessage("%s %s","Testing",100)) as string and at that str gets assigned to Bad Pointer and if(*str) statement throws Access Violation exception which is valid here. But How can I prevent invalid string to get added into stringstream??
Related
I have a function that counts the number of occurences of a string in a char array. Calling this function normally with findword(copy, "polar") works perfectly fine and prints an int that's the number of times the string "polar" occurs in the char array "copy". Calling the function via a pthread however gives me compilation issues and I don't know why. This is my first time implementing multithreading.
Here is the function I want to call:
void findword(char *str, string word)
{
char *p;
vector<string> a;
p = strtok(str, " ");
while (p != NULL)
{
a.push_back(p);
p = strtok(NULL, " ");
}
int c = 0;
for (int i = 0; i <= a.size(); i++)
if (word == a[i])
c++;
printf("%d", c);
}
And here is the thread I'm trying to create that is supposed to call the function:
struct findwordargs {
char *str;
string word;
};
struct findwordargs firstwordArguments;
firstwordArguments.str = copy;
firstwordArguments.word = "polar";
pthread_t thread_id = 1;
pthread_create(&thread_id, NULL, findword, (void *)(&firstwordArguments));
pthread_join(thread_id, NULL);
whenever I compile using g++ and the -pthread flag I get this compile error:
error: invalid conversion from ‘int (*)(char*, std::string)’ {aka ‘int (*)(char*, std::__cxx11::basic_string<char>)’} to ‘void* (*)(void*)’ [-fpermissive]
101 | pthread_create(&thread_id, NULL, findword, (void *)(&firstwordArguments));
All the necessary header files are included, thank you for the help.
Your findword() function does not match the signature that pthread_create() requires:
void *(*start_routine)(void *)
Try this instead:
struct findwordargs
{
char *str;
std::string word;
};
void* findword(void *param)
{
findwordargs *args = static_cast<findwordargs*>(param);
std::vector<std::string> a;
char *p = strtok(args->str, " ");
while (p) {
a.push_back(p);
p = strtok(NULL, " ");
}
int c = 0;
for (size_t i = 0; i < a.size(); ++i) {
if (args->word == a[i])
c++;
}
printf("%d", c);
/* alternatively, using more C++-ish routines:
std::istringstream iss(args->str);
std::string word;
while (iss >> word) a.push_back(word);
std::cout << std::count(a.begin(), a.end(), args->word);
*/
return NULL;
}
...
findwordargs firstwordArguments;
firstwordArguments.str = copy;
firstwordArguments.word = "polar";
pthread_t thread_id = 1;
pthread_create(&thread_id, NULL, findword, &firstwordArguments);
pthread_join(thread_id, NULL);
That being said, there is no point in creating a thread just to immediately join it. That blocks the calling thread until the spawned thread exits, which is the same effect as simply calling the function directly, but without the overhead of context switching between threads:
void findword(const std::string &str, const std::string &word)
{
std::vector<std::string> a;
std::istringstream iss(str);
std::string word;
while (iss >> word) a.push_back(word);
std::cout << std::count(a.begin(), a.end(), word);
}
...
findword(copy, "polar");
Is there a reason you're using pthreads instead of std::thread? If so, then ignore me. This is what I would do:
std::thread myThread([=](){ findword(copy, "polar"); });
myThread.join();
-or-
myThread.detach(); // If appropriate.
This depends on something resembling modern C++.
Here is a problem. When I try to convert it by using strncpy_s, array has some type of "trash data" from memory in the end of it. Even when I fill buffer with "\0". How to convert it clear?
typedef class Ryadok {
private:
int LengthOf = 0;
char text[20];
string* address;
public:
Ryadok(string strin) {
this->text[0] = '\0';
memset(text, '\0', sizeof(text));
strncpy_s(text, strin.c_str(), sizeof(text) - 1);
this->address = &strin;
for (int i = 0; i < sizeof(strin); i++) {
cout << this->text[i];
}
}
~Ryadok() {
}
}*cPtr;
int main()
{
Ryadok example("sdsdfsdf");
}
The idea to use c_str() function to convert the std::string to a a-string. Then we can simply call strcpy() function to copu the c-string into char array
std::string s = "Hello World!";
char cstr[s.size() + 1];
strcpy(cstr, s.c_str()); // or pass &s[0]
std::cout << cstr << '\n';
return 0;
When using the strncpy_s function you tell it to copy as many chars as will fit into your buffer "text". Since the string you create the "example" instance with is shorter, the copy function will keep going after the end of the actual string.
That is where your garbage comes from. Even worse you risk a Segmentation Fault this way. Your code might access parts of the RAM it is not allowed to read from. That will cause it to crash.
You are right though to copy the data pointed to by the return of c_str(). The pointer returned by c_str() points to data that belongs to the std::string object and might be changed or even invalidated by that object. (Read more here)
Here's a modified version of your code that should avoid the garbage:
typedef class Ryadok {
private:
int LengthOf = 0;
char text[20];
string* address;
public:
Ryadok(string strin) {
this->text[0] = '\0';
memset(text, '\0', sizeof(text));
if(strin.length()+1 <= sizeof(text)) {
strncpy_s(text, strin.c_str(), strin.length()+1);
} else {
//some error handling needed since our buffer is too small
}
this->address = &strin;
for (int i = 0; i < sizeof(strin); i++) {
cout << this->text[i];
}
}
~Ryadok() {
}
}*cPtr;
int main()
{
Ryadok example("sdsdfsdf");
}
I am trying to reverse a char* by using a stack.
stack<char> scrabble;
char* str = "apple";
while(*str)
{
scrabble.push(*str);
str++;
count++;
}
while(!scrabble.empty())
{
// *str = scrabble.top();
// str++;
scrabble.pop();
}
In the second While-loop, I'm not sure how to assign each char from the stack's top to the char* str.
When you have a string defined using
char* str = "apple";
you are not supposed to change the value of the string. Changing such a string causes undefined behavior. Instead, use:
char str[] = "apple";
In the while loops, use an index to access the array instead of incrementing str.
int i = 0;
while(str[i])
{
scrabble.push(str[i]);
i++;
count++;
}
i = 0;
while(!scrabble.empty())
{
str[i] = scrabble.top();
i++;
scrabble.pop();
}
You can also iterate a pointer to the char[] if you'd like
char str[] = "apple";
char* str_p = str;
int count = 0;
while(*str_p)
{
scrabble.push(*str_p);
str_p++;
count++;
}
// Set str_p back to the beginning of the allocated char[]
str_p = str;
while(!scrabble.empty())
{
*str_p = scrabble.top();
str_p++;
scrabble.pop();
}
I'm studying C/C++ and the exercise I'm doing is to create a program which evaluates an arithmetic expression.
To complete the exercise, I need a general purpose function which is able to tokenize a string.
As the size of the string to parse is not known at compile time, I have to allocate dynamically some data in the heap.
After the work is done, the memory in the heap can be released.
My question is simple: I'm releasing the memory correctly? See the questions in the comments.
Tokenize function
char** Tokenize(const char delimiter, const char* string)
{
const char* pString = string;
char** tokens = new char*[strlen(string)];
char* buffer = new char[strlen(string)];
char* pointer = buffer;
int c = 0;
for (int k = 0; k < strlen(string); k++)
{
if (string[k] == delimiter)
{
buffer[k] = '\0';
tokens[c] = pointer;
pointer = buffer + k + 1;
c++;
continue;
}
buffer[k] = string[k];
}
tokens[c] = nullptr;
return tokens;
}
The main function which tests Tokenize function and relases the heap.
int main()
{
char** tokens = Tokenize('.', "192.168.1.1");
char** startTokensPointer = tokens;
char* startBufferPointer = *tokens;
while (*tokens != nullptr)
{
cout << *tokens << endl;
tokens++;
}
delete[] startTokensPointer; //Releases tokens??
delete[] startBufferPointer; //Releases buffer??
system("PAUSE");
}
You are not deallocating buffer correctly. If none of the chars in string is equal to delimiter the code in this if statement :
if (string[k] == delimiter)
will never be executed and c will remain 0. Then this line :
tokens[c] = nullptr;
will set the first element of tokens that is stored in startBufferPointer to nullptr. In that case you are leaking buffer as the pointer to buffer is "forgotten" in main.
tokens is deallocated correctly in all cases.
Yes, there is no memory leak, but why not use a type that makes it guaranteed?
struct Tokens
{
explicit Tokens(size_t len) : tokens(new char*[len]), buffer(new char[len])
{ }
std::unique_ptr<char*[]> tokens;
std::unique_ptr<char[]> buffer;
};
Tokens Tokenize(const char delimiter, const char* string)
{
auto len = strlen(string);
Tokens result(len);
char* pointer = result.buffer.get();
int c = 0;
for (size_t k = 0; k < len; k++)
{
if (string[k] == delimiter)
{
result.buffer[k] = '\0';
result.tokens[c] = pointer;
pointer = result.buffer.get() + k + 1;
c++;
continue;
}
result.buffer[k] = string[k];
}
result.tokens[c] = nullptr;
return result;
}
int main()
{
auto tok = Tokenize('.', "192.168.1.1");
char** tokens = tok.tokens.get();
while (*tokens != nullptr)
{
cout << *tokens << endl;
tokens++;
}
}
Now all the memory is managed automatically and it's almost impossible to leak.
#define printm(p) writeToAnalyticsFile p
void writeToAnalyticsFile (const char* format, ...)
{
std::string errorLog;
std::string headerLine = "\"errorText\":";
FILE *fp = fopen( "Analyse.txt", "w" );
if( 0 == fp )
{
}
else
{
va_list args;
va_start (args, format);
vsprintf (const_cast<char*>(errorLog.c_str()),format, args);
va_end (args);
fputs(headerLine.c_str(),fp);
fputs("\"",fp);
fputs( errorLog.c_str(), fp );
fputs("\"",fp);
fclose(fp);
}
}
class abc
{
public:
static const char * func()
{
std::string str = "john";
return str.c_str();
}
};
int main()
{
printm(("My Name is %s and surname is %s and age is %d",abc::func(),"john",25));
return 0;
}
I basically want to replace printm((--- )) with writeToAnalytics(--) which writes data to file.
I am getting Segmentation Fault with below code.
Problem is with calling abc::func() in main. Is it because of local storage of str in func()?
The func function is incorrect, as it is returning an invalid pointer:
static const char * func()
{
std::string str = "john";
return str.c_str();
}
The string is destroyed at the end of the function, and therefore the pointer str.c_str() is a dangling pointer - pointing to a string that doesn't exist any more.
Solution is to just return "john". Literals last forever.
static const char * func()
{
return "john";
}
Or, better still, just return the string,
static string func()
{
std::string str = "john";
return str;
}
and use abc::func().c_str() at the call site.
(There may be other problems, but this is the most obvious to me)