I'm trying to write code that sets the name of a Student object to a new name, but I'm coming across memory leak errors when creating a character array. I assume it has to do with /0 at the end of the array and isn't terminating properly, but I don't know how to properly fix this. Thanks for the help.
#include "student.h"
#include <string>
#include <cstring>
#include <iostream>
using namespace std;
Student::Student(const char * const name, int perm) {
this->setName(name);
this->setPerm(perm);
}
int Student::getPerm() const {
return this->perm;
}
const char * const Student::getName() const {
return this->name;
}
void Student::setPerm(const int perm) {
this->perm = perm;
}
void Student::setName(const char * const newName) {
this->name = new char[strlen(newName)+1];
// this->name[srtlen(newName)+1] = '/0'; <---- My suggested fix, but doesn't work
strcpy(this->name,newName);
}
Student::Student(const Student &orig) {
this->setName(orig.getName());
this->setPerm(orig.getPerm());
}
Student::~Student() {
delete this->name;
this->perm = 0;
}
This is the valgrind error:
==13814== Invalid read of size 1
==13814== at 0x4C2BA12: strlen (vg_replace_strmem.c:454)
==13814== by 0x4F56FD6: UnknownInlinedFun (char_traits.h:267)
==13814== by 0x4F56FD6: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (basic_string.h:456)
==13814== by 0x401ED8: Student::toString[abi:cxx11]() const (student.cpp:64)
==13814== by 0x401A46: main (testStudent00.cpp:14)
==13814== Address 0x5302e8 is not stack'd, malloc'd or (recently) free'd
==13814==
Your assumption that you needed to add the 0 terminator is wrong, strcpy() will do that for you. Your attempt of doing so adds the 0 terminator one byte past the space you allocated (remember, array indexes start at zero), and the syntax is also wrong, you would need to do:
this->name[strlen(newName)] = '\0';
However, to fix your memory leak You need to delete the previous string, like
void Student::setName(const char * const newName)
{
delete [] this->name;
this->name = new char[strlen(newName)+1];
strcpy(this->name,newName);
}
Student::Student(const Student &orig) :
name(0) {
this->setName(orig.getName());
this->setPerm(orig.getPerm());
}
Student::~Student() {
delete [] this->name;
this->perm = 0;
}
Now, for this to work, you also need to fix your constructor and copy constructor to initialize the name member, so it isn't an uninitialized pointer for the first call to the setName() function, and you need to add an assignment operator too, so you can properly handle assignments.
Student::Student(const char * const name, int perm) :
name(0)
{
this->setName(name);
this->setPerm(perm);
}
Student &operator=(const Student &orig) {
this->setName(orig.getName());
this->setPerm(orig.getPerm());
}
Also, consider using std::string instead of your current low level way of handling strings, that way you don't need to even implement a copy constructor, assignment operator and destructor for this class, nor deal with correctly managing memory.
Related
So I've been working on modifying the thingsboard arduino library to support device provisioning. I've duplicated/renamed/modified a handful of functions in the library to support pointing to the correct topics, and added the supporting code in my main application to make use of them. However, I am now getting a compiler error in a section of the library code I did not touch. I'm hoping someone can point out what I goofed up, as it appears like it should be a fairly simple fix if I can find it.
This is the bit of code giving me the error-
inline Telemetry(const char *key, T val)
:m_type(TYPE_INT), m_key(key), m_value() { m_value.integer = val; }
Here is the error -
In file included from src\main.cpp:12:0:
.pio\libdeps\win\ThingsBoard\src/ThingsBoard.h: In instantiation of 'Telemetry::Telemetry(const char*, T) [with T = String; <template-parameter-1-2> = ArduinoJson6172_91::enable_if<false, void>]':
src\main.cpp:514:33: required from here
.pio\libdeps\win\ThingsBoard\src/ThingsBoard.h:46:64: error: cannot convert 'String' to 'int' in assignment
:m_type(TYPE_INT), m_key(key), m_value() { m_value.integer = val; }
Here's the bulk of what I added to my main code to handle device registration.
RPC_Response processDeviceRegistration(const RPC_Data &data)
{
Serial.println("Received the device registration response");
if(data["status"]=="SUCCESS"){
String credential = data["credentialsValue"];
EEPROM.write(10, sizeof(credential));
EEPROM.writeString(20, (String)credential);
dr.DR_Unsubscribe();
return RPC_Response("registration response", true);
}
else{
Serial.println("Device registration failed");
return RPC_Response("registration response", false);
}
}
const size_t callbacks_size = 2;
RPC_Callback callbacks[callbacks_size] = {
{ "device_registration", processDeviceRegistration }
};
void reinitialize()
{
if (!dr.RPC_Subscribe(callbacks, 1)) {
Serial.println("Failed to subscribe for RPC");
return;
}
dr.loop();
String IMEI = modem.getIMEI();
const int data_items = 3;
Telemetry data[data_items] = {
Telemetry("deviceName", IMEI),
Telemetry("provisionDeviceKey", provision_device_key),
Telemetry("provisionDeviceSecret", provision_device_secret),
};
if (!dr.sendDR(data, data_items)){
Serial.println("Device registration send failed");
}
If it would be helpful, I can fork and upload the full library code and post a link to my github.
----- Edit -----
Upon further investigation, it appears the template for the Telemetry class is detecting the IMEI variable as an integer rather than a string and trying to convert it for some reason. I have no idea why, or how to fix it. Any suggestions would be greatly appreciated.
Well then, helps if I take a few minutes to actually understand the code I didn't write that is giving me grief. There was no handler in the Telemetry constructor for a character array or string type variable. Added that and now everything is working :)
Full Telemetry constructor below -
inline Telemetry()
:m_type(TYPE_NONE), m_key(NULL), m_value() { }
// Constructs telemetry record from integer value.
// EnableIf trick is required to overcome ambiguous float/integer conversion
template<
typename T,
typename = ARDUINOJSON_NAMESPACE::enable_if<ARDUINOJSON_NAMESPACE::is_integral<T>::value>
>
inline Telemetry(const char *key, T val)
:m_type(TYPE_INT), m_key(key), m_value() { m_value.integer = val; }
// Constructs telemetry record from boolean value.
inline Telemetry(const char *key, bool val)
:m_type(TYPE_BOOL), m_key(key), m_value() { m_value.boolean = val; }
// Constructs telemetry record from float value.
inline Telemetry(const char *key, float val)
:m_type(TYPE_REAL), m_key(key), m_value() { m_value.real = val; }
// Constructs telemetry record from string value.
inline Telemetry(const char *key, const char *val)
:m_type(TYPE_STR), m_key(key), m_value() { m_value.str = val; }
// Constructs telemetry record from string value.
inline Telemetry(const char *key, char *val)
:m_type(TYPE_STR), m_key(key), m_value() { m_value.str = val; }
I wondered if there is an option to also hand over the current processed index with QtConcurrent::mapped(someVector, &someFunction)) (also filter, filtered, map,...)
What I want: I want to do something with the elements in someVector based on the current index in it. but since the function someFunction is only taking the type T which is also used for the QVector<T> vector.
What I did: Because I needed this, I created a QVector<std::pair<int, T>> and manually created the index for the elements.
Since this requires more space and is not a nice solution, I thought maybe there could be another solution.
Docs: https://doc.qt.io/qt-5/qtconcurrent-index.html
If your input is a QVector, you can make use of the fact that QVector stores all the elements contiguously. This means that given a reference to an element e in a QVector v, then the index of e can be obtained by:
std::ptrdiff_t idx = &e - &v.at(0);
Below is a complete example using QtConcurrent::mapped:
#include <iterator>
#include <numeric>
#include <type_traits>
#include <utility>
#include <QtCore>
#include <QtConcurrent>
// lambda functions are not directly usable in QtConcurrent::mapped, the
// following is a necessary workaround
// see https://stackoverflow.com/a/49821973
template <class T> struct function_traits :
function_traits<decltype(&T::operator())> {};
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const> {
// specialization for pointers to member function
using functor_type = ClassType;
using result_type = ReturnType;
using arg_tuple = std::tuple<Args...>;
static constexpr auto arity = sizeof...(Args);
};
template <class Callable, class... Args>
struct CallableWrapper : Callable, function_traits<Callable> {
CallableWrapper(const Callable &f) : Callable(f) {}
CallableWrapper(Callable &&f) : Callable(std::move(f)) {}
};
template <class F, std::size_t ... Is, class T>
auto wrap_impl(F &&f, std::index_sequence<Is...>, T) {
return CallableWrapper<F, typename T::result_type,
std::tuple_element_t<Is, typename T::arg_tuple>...>(std::forward<F>(f));
}
template <class F> auto wrap(F &&f) {
using traits = function_traits<F>;
return wrap_impl(std::forward<F>(f),
std::make_index_sequence<traits::arity>{}, traits{});
}
int main(int argc, char* argv[]) {
QCoreApplication app(argc, argv);
// a vector of numbers from 0 to 500
QVector<int> seq(500, 0);
std::iota(seq.begin(), seq.end(), 0);
qDebug() << "input: " << seq;
QFuture<int> mapped = QtConcurrent::mapped(seq, wrap([&seq](const int& x) {
// the index of the element in a QVector is the difference between
// the address of the first element in the vector and the address of
// the current element
std::ptrdiff_t idx = std::distance(&seq.at(0), &x);
// we can then use x and idx however we want
return x * idx;
}));
qDebug() << "output: " << mapped.results();
QTimer::singleShot(100, &app, &QCoreApplication::quit);
return app.exec();
}
See this question for a related discussion. Note that the linked question has a cleaner answer that involves the usage of zip and counting iterators from boost (or possibly their C++20 ranges counterparts), but I don't think that this would play well with QtConcurrent::map when map slices the sequence into blocks, and distributes these blocks to multiple threads.
I am shifting from Python to C so bit rusty on the semantics as well as coding habit. In Python everything is treated as an object and objects are passed to functions. This is not the case in C so I want to increment an integer using pointers. What is the correct assignment to do so. I want to do it the following way but have the assignments wrong:
#include <stdio.h>
int i = 24;
int increment(*i){
*i++;
return i;
}
int main() {
increment(&i);
printf("i = %d, i);
return 0;
}
I fixed your program:
#include <stdio.h>
int i = 24;
// changed from i to j in order to avoid confusion.
// note you could declare the return type as void instead
int increment(int *j){
(*j)++;
return *j;
}
int main() {
increment(&i);
printf("i = %d", i);
return 0;
}
Your main error was the missing int in the function's argument (also a missing " in the printf).
Also I would prefer using parentheses in expressions as *j++ and specify exactly the precedence like I did in (*j)++, because I want to increment the content of the variable in the 'j' location not to increment the pointer - meaning to point it on the next memory cell - and then use its content.
I am sorry that I cannot support my question with some code (I didnt understand how to structure it so it would be accepted here), but I try anyway.
If I understand correctly, a struct that references a struct of same type would need to do this with contained pointer for reference. Can this pointer reference to allocated space on the stack (instead of the heap) without creating segmentation fault? -
how should this be declared?
Yes, you can use pointers to variables on the stack, but only when the method that provides that stack frame has not returned. For example this will work:
typedef struct
{
int a;
float b;
} s;
void printStruct(const s *s)
{
printf("a=%d, b=%f\n", s->a, s->b);
}
void test()
{
s s;
s.a = 12;
s.b = 34.5f;
printStruct(&s);
}
This will cause an error however, as the stack frame would have disappeared:
s *bad()
{
s s;
s.a = 12;
s.b = 34.5f;
return &s;
}
EDIT: Well I say it will cause an error, but while calling that code with:
int main()
{
test();
s *s = bad();
printStruct(s);
return 0;
}
I get a warning during compilation:
s.c:27:5: warning: function returns address of local variable [enabled by default]
and the program appears to work fine:
$ ./s
a=12, b=34.500000
a=12, b=34.500000
But it is, in fact, broken.
You didn't say what language you are working in, so assuming C for now from the wording of your question... the following code is perfectly valid:
typedef struct str_t_tag {
int foo;
int bar;
struct str_t_tag *pNext;
} str_t;
str_t str1;
str_t str2;
str1.pNext = &str2;
In this example both str1 and str2 are on the stack, but this would also work if either or both were on the heap. The only thing you need to be careful of is that stack variables will be zapped when they go out of scope, so if you had dynamically allocated str1 and passed it back out of a function, you would not want str1->pNext to point to something that was on the stack within that function.
In other words, DON'T DO THIS:
typedef struct str_t_tag {
int foo;
int bar;
struct str_t_tag *pNext;
} str_t;
str_t *func(void)
{
str_t *pStr1 = malloc(sizeof(*pStr1));
str_t str2;
pStr1->pNext = &str2;
return pStr1; /* NO!! pStr1->pNext will point to invalid memory after this */
}
Not sure if this is specifically a C/C++ question, but I'll give C/C++ code as example in anyway.
The only way you can declare it: (with minor variations)
typedef struct abc
{
struct abc *other;
} abc;
other can point to an object on the stack as follows:
abc a, b; // stack objects
b.other = &a;
This is not a question about scope, so I'll skip commenting on possible issues with doing the above.
If, however, you want to assign it to a dynamically created object, there's no way this object can be on the stack.
abc b;
b.other = malloc(sizeof(abc)); // on the heap
My code
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
void getData(short int *number, char *string)
{
printf("\nPlease enter a number greater than zero: ");
scanf("%hd", number);
printf("Please enter a character string: ");
scanf("%s", string);
}
void echoPair(short int *number, char *string)
{
printf("Number: %hd Character(s): %s\n", *number, string);
}
int main()
{
short int *number = 0;
char string[32] = {0};
printf("This program will ask you to enter a number greater than zero and \na character string with less than 32 characters \ninput.");
getData(&number, &string);
echoPair(&number, &string);
return(0);
}
The code works fine, but I receive these compiler warnings
warning: passing argument 1 of ‘getData’ from incompatible pointer type
warning: passing argument 2 of ‘getData’ from incompatible pointer type
warning: passing argument 1 of ‘echoPair’ from incompatible pointer type
warning: passing argument 2 of ‘echoPair’ from incompatible pointer type
If do this
getData(number, string);
echoPair(number, string);
The warnings go away, but the program gets a "Segmentation fault: 11" after I enter the first number in the getData function.
Anyone know how to remove the warnings and keep the program working?
Thanks
There are a number of problems here.
First, the line:
short int *number = 0;
should be:
short int number = 0;
Because you used the former, it gave you a null pointer to a short. That's not what you want since the first dereference of that beast will probably crash your code (or, worse, not crash your code but cause strange behaviour).
Secondly, you don't need to pass in the address of strings, they automatically decay to an address, so change:
getData (&number, &string);
echoPair (&number, &string);
to:
getData (&number, string);
echoPair (&number, string); // but see last point below.
And, last of all, you don't need to pass in the address just to print it, you can just pass in the value, hence:
echoPair (&number, &string);
becomes:
echoPair (number, string);
As a whole, I think what you want is:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
void getData(short int *number, char *string) {
printf("\nPlease enter a number greater than zero: ");
scanf("%hd", number);
printf("Please enter a character string: ");
scanf("%s", string);
}
void echoPair(short int number, char *string) {
printf("Number: %hd Character(s): %s\n", number, string);
}
int main (void) {
short int number = 0;
char string[32] = {0};
printf("Blah blah ...");
getData(&number, string);
echoPair(number, string);
return(0);
}
As an aside, you don't ever want to see unbounded string scans like:
scanf ("%s", string);
in production-ready code. It's a buffer overflow vulnerability waiting to happen, since you don't control what the user will input. In your particular case, the user entering more than (about) 30 characters may cause all sorts of weird behaviour.
The scanf function is for scanning formatted text, and there's not many things more unformatted than user input :-)
If you want a robust user input function, see here.
You declare the local variable number as a pointer to short int. You then pass a pointer to it to getData and echoPair. So you're passing a pointer to a pointer, which is the wrong type. Probably you want to declare number as just a short int rather than a pointer.