Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 6 years ago.
Improve this question
I want to make a custom String class for C++. But when I do this:
g++ test.cpp sys/Base.h sys/Base.cpp
I get this error:
sys/Base.cpp: In function 'const char* Base::toChar()':
sys/Base.cpp:57:13: error: 'strval' was not declared in this scope
return strval;
^
sys/Base.cpp: In function 'std::string Base::toStr()':
sys/Base.cpp:60:20: error: 'strval' was not declared in this scope
return string(strval);
^
test.cpp
#include "sys/Base.h"
int main() {
Base::write("Hello there.\n");
return 0;
}
sys/Base.h
// Header file handling
#ifndef ARAVK_BASE_H
#define ARAVK_BASE_H
// Includes
#include <string>
// Global variables
#define EXIT_YAY 0
#define EXIT_ERR 1
using namespace std;
namespace Base {
// Classes:
class String {
static const char* strval;
public:
// Constructors:
String();
String(char[]);
String(const char*);
String(string);
// Destructors:
~String();
// Operators:
// =
void operator=(const String&);
void operator=(const char*&);
void operator=(const string&);
// Conversion:
const char* toChar() const;
string toStr() const;
};
// Functions:
// Input-Output:
// Write:
void write(String);
void write(string);
void write(const char*);
// Read:
String read();
// Executing:
String run(String);
}
#endif
sys/Base.cpp
// Including
#include "Base.h"
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <cstdio>
#include <iostream>
#include <memory>
#include <stdexcept>
// Global variables
#define EXIT_ERR 1
#define EXIT_YAY 0
/* ------------------------ */
using namespace std;
namespace Base {
// Classes
// String functions
// Constructors
String::String() {
const char* strval = "";
}
String::String(const char* str) {
const char* strval = str;
}
String::String(string str) {
const char* strval = str.c_str();
}
String::String(char str[]) {
const char* strval = str;
}
// Destructors
String::~String() {
delete strval;
}
// Operators
// =
void String::operator=(const String &strp) {
strval = strp.toChar();
}
void String::operator=(const char* &strp) {
strval = strp;
}
void String::operator=(const string &strp) {
strval = strp.c_str();
}
// Conversion:
const char* toChar() {
return strval;
}
string toStr() {
return string(strval);
}
// Functions:
// Input-Output:
// Write
void write(String str) { printf(str.toChar()); }
void write(const char* str) { printf(str); }
void write(string str) { printf(str.c_str()); }
// Read
String read() { char str[100]; scanf("%s", str); return String(str); }
//TODO: More to come
// Executing
/*String run(String command) {
const char* cmd = command.toChar();
char buffer[128];
string result = "";
std::shared_ptr<FILE> pipe(popen(cmd, "r"), pclose);
if (!pipe) throw runtime_error("popen() failed!");
while (!feof(pipe.get())) {
if (fgets(buffer, 128, pipe.get()) != NULL)
result += buffer;
}
return String(result);
}*/
String run(String command) {
char buffer[128];
std::string result = "";
const char* cmd = command.toChar();
FILE* pipe = popen(cmd, "r");
if (!pipe) throw std::runtime_error("popen() failed!");
try {
while (!feof(pipe)) {
if (fgets(buffer, 128, pipe) != NULL)
result += buffer;
}
} catch (...) {
pclose(pipe);
throw;
}
pclose(pipe);
return String(result);
}
}
I'm not sure why this is happening. I think it's related to how I've declared/defined the const char* 'strval'. Can anybody help?
P.S: If the answer is too big, this project is on Github: AravK/C-Applications
Let's take a look at your constructor:
String::String() {
const char* strval = "";
}
This declares a local variable called strval. The variable is local to the constructor; it doesn't exist once execution of the constructor completes.
What you need instead is a member variable - declare it inside the class, but not inside a member method or constructor. In fact, you have already defined it as such in the header file:
class String {
static const char* strval;
So, remove the const char * from your constructor and add a class qualifier, so that the line becomes an assignment to the existing variable, rather than creation of a local:
String::String() {
String::strval = "";
}
And also change the return statement that is giving you the error:
return String::strval;
Or perhaps - and this is likely what you really wanted - remove the static qualifier from the variable definition, and change the constructor instead to just:
String::String() {
strval = "";
}
Furthermore, your destructor incorrectly deletes data that was not necessarily dynamically allocated, or which may belong to another object:
String::~String() {
delete strval;
}
This requires re-working. At the moment the simplest solution is to remove the delete strval altogether.
Your read() function potentially instigates a buffer overflow, by using scanf("%s") with a fixed size buffer and unknown input size:
char str[100]; scanf("%s", str); return String(str);
Finally, your command line:
g++ test.cpp sys/Base.h sys/Base.cpp
... should not include the header file (Base.h). You are specifying the units you want compiled, and Base.h is already included in Base.cpp; it is not a standalone unit that should be compiled invidually.
yes you did not define the variable in your class as a field.
there is 3 locals déclaration in your constructors.
just add it the way you have done in the header.
static const char* strval
and remove the définition in your constructors. Just keep the assignement part.
regards
Related
I have a class in a header file as follows:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
class ShowTicket {
public:
bool is_sold(void){
if (sold_status == true){
return true;
}
else{
return false;
}
}
void sell_seat(void){
sold_status = true;
}
string print_ticket(void){
ostringstream sout;
if(sold_status == true){
sout<<row<<" "<<seat_number<<"sold";
}
else{
sout<<row<<" "<<seat_number<<"available";
}
return sout.str();
}
bool sold_status;
const char* row;
const char* seat_number;
ShowTicket(const char* Row, const char* SeatNumber):
sold_status{false},
row(Row),
seat_number(SeatNumber)
{}
};
The main function to test this class is as follows:
#include <iostream>
#include <string>
#include <sstream>
#include "showticket.h"
using namespace std;
int main () {
ShowTicket myticket1("AA","101");
ShowTicket myticket2("AA","102");
if(!myticket1.is_sold())
myticket1.sell_seat ();
cout << myticket1.print_ticket() << endl;
cout << myticket2.print_ticket() << endl;
return 0;
}
When myticket 1 and 2 are created there is an error "No matching constructor for initialization of 'ShowTicket" but I believe my constructor accepts these parameters so I'm not sure how to resolve.
Any advice would be appreciated.
By the looks of it, you only want to supply two arguments, but your constructor requires three:
ShowTicket(const char* row, const char* seat_number, bool sold_status){
sold_status = false;
}
The body of the constructor makes be believe that you want to initialize a newly created ShowTicket with sold_status set to false. You can do that directly in the member initializer list:
ShowTicket(const char* row, const char* seat_number) : // note the colon
sold_status{false} // <- here
{}
If that's not the case, you can make sold_status have a default value, below it's set to false:
ShowTicket(const char* row, const char* seat_number, bool sold_status = false) :
sold_status{sold_status}
{}
I also recommend using different names for the arguments and the member variables. It can easily get messy otherwise:
ShowTicket(const char* row, const char* seat_number, bool SoldStatus = false) :
sold_status{SoldStatus}
{}
Also note that you don't actually allocate memory for and save the row and seat_number in the constructor. Calling your print_ticket function will therefore cause undefined behavior. I recommend that you replace the raw pointers and replace them with std::strings:
std::string row;
std::string seat_number;
You can now save all in the constructor and not have to worry about memory management:
ShowTicket(const char* Row, const char* SeatNumber, bool SoldStatus = false) :
sold_status{SoldStatus},
row(Row),
seat_number(SeatNumber)
{}
You may also want to consider taking the row and seat_number arguments as const std::string&s or std::string_views (since C++17) to make it easier to work with in general.
I have found a stack-use-after-scope error in our code-base (g++ -fsanitize=address), and would like to know if that's a valid concern, and I should go and fix every occurrence of such pattern, or is it a false positive from address sanitizer?
Minimal and simplified example is as follows:
#include <string>
#include <stdio.h>
struct MyStr
{
MyStr() = default;
MyStr(const char *s) : text(s) {};
MyStr substr(size_t length) const
{
auto begin = text.begin();
auto end = begin + length;
return MyStr(std::string(begin, end));
}
const char *c_str()
{
return text.c_str();
}
private:
explicit MyStr(std::string s): text(std::move(s)){};
std::string text;
};
struct Other
{
std::string text;
Other(const std::string &s): text(s){};
};
void usage(const char *s)
{
Other other(s); // BAM!!!
}
int main() {
MyStr str("use-after-scope-example");
auto cs = str.substr(2).c_str();
usage(cs);
return 0;
}
This is C++11 if that's of any importance, and compiler is g++ (SUSE Linux) 11.1.1 20210617 [revision 79c1185de4]
Yes, the error is correctly reported (Although BAM!!! seems to be misplaced). This line:
auto cs = str.substr(2).c_str();
declares cs as pointer to character buffer, which is removed once the temporary returned by str.substr(2) is destroyed (which happens in the end of the expression).
#include <iostream>
class Model
{
public:
Model(const char *a)
{
message=a;
}
const char *car() { return message; }
const char *message;
};
class ModelCar
{
public:
ModelCar(const char *sn, const char *b="c")
{
filename=strdup(sn);
f=fopen(sn,b);
if (f==NULL)
{
throw Model("File can't be opened");
}
}
~ModelCar()
{
delete [] filename;
if (fclose(f)<0)
{
throw Model("File can't be closed");
}
}
void read(char *buf, int size)
{
if (fread(buf, 1, size, f)!=size)
{
throw Model("File can't be read");
}
}
const char *filename;
FILE *f;
};
Why I am getting error: ‘strdup’ was not declared in this scope , I tried and add #include <string.h> but still getting error
Can anyone please help me what is wrong in this code
First of all I suggest you to fix some problems with the code:
1.
delete [] filename;
filename=strdup(sn);
Okay your delete function suggests that your filename is a dynamic array which you never intialized. Also have you looked at what strdup returns, it returns a dynamic char, not an dynamic array. I would suggest you change:
delete [] filename;
to
free(filename);
#include <iostream>
#include <string.h>
using namespace std;
void ArrayTimesThree(char*, const char*);
int main()
{
char s1[200], s2[200], circleword[200];
cin.getline(s1, 200);
cin.getline(s2, 200);
ArrayTimesThree(circleword, s1);
cout<<circleword[1];
}
void ArrayTimesThree(char *dest[], char *source[])
{
*dest[0] = NULL;
strcat(*dest, *source);
strcat(*dest, *source);
strcat(*dest, *source);
}
main.cpp|21|error: cannot convert 'char (*)[200]' to 'char**' for argument '1' to 'void ArrayTimesThree(char**, char**)'
You're passing ArrayTimesThree a char*, however, in the method signature you're telling it to expect a char**. Don't forget that that using the [] operator counts as a dereference. Try this:
#include <iostream>
#include <string.h>
using namespace std;
void ArrayTimesThree(char*, char*);
int main()
{
char s1[200], s2[200], circleword[200];
cin.getline(s1, 200);
cin.getline(s2, 200);
ArrayTimesThree(circleword, s1);
cout<<circleword[1];
return 0;
}
void ArrayTimesThree(char *dest, char source[])
{
dest[0] = '\0';
strcat(dest, source);
strcat(dest, source);
strcat(dest, source);
}
Disclaimer: I'm not sure what exactly you're expecting out of this code, so I cannot guarantee the logic is correct; however, this will take care of your compiler errors and seems to function correctly for how the code is written.
The problem is really just because your initial declaration of ArrayTimesThree (which is the 'correct' one) doesn't match the definition you later give (which is wrong, in fact). Change your definition as below and it works:
void ArrayTimesThree(char* dest, const char* source) // Needs to be the same as in the previous declaration!
{
dest[0] = '\0'; // Don't assign a string pointer to NULL! Instead, set its first character to the nul character
// strcpy(dest, ""); // ALternatively, use strcpy with an empty string to clear "dest"
strcat(dest, source); // strcat takes char* and const char* arguments ...
strcat(dest, source); // ... so there is no need to 'deference the values ...
strcat(dest, source); // ... now that the argument types have been 'corrected'
}
Incidentally, I notice that the input value for s2 in your main function is never actually used … is this what you intend, for now?
This is only part of an overall program and compiles and runs fine in Windows, however it does not like my strcpy in Linux/Unix. What am I doing wrong and how can I fix it? Also a note, I am not allowed to use string, only cstring.
Song.cpp
#include "Song.h"
Song::Song()
{
}
Song::~Song()
{
}
Song::Song(char* title, char* artist, char* duration, char* album)
{
strcpy(this->title,50,title);
strcpy(this->artist, 50, artist);
strcpy(this->duration, 50, duration);
strcpy(this->album, 50, album);
}
void Song::setTitle(char* title)
{
this->title= title;
}
void Song::setArtist(char* artist)
{
this->artist = artist;
}
void Song::setDuration(char* duration)
{
this->duration= duration;
}
void Song::setAlbum(char* album)
{
this->album= album;
}
char* Song::getTitle()
{
return this->title;
}
char* Song::getArtist()
{
return this->artist;
}
char* Song::getDuration()
{
return this->duration;
}
char* Song::getAlbum()
{
return this->album;
}
Song.h
#include <iostream>
#include <iomanip>
#include <fstream>
#include <cstring>
#include <cctype>
using namespace std;
class Song
{
private:
char* title;
char* artist;
char* duration;
char* album;
public:
Song();
~Song();
Song(char* title, char* artist, char* duration, char* album);
void setTitle(char* title);
void setArtist(char* artist);
void setDuration(char* duration);
void setAlbum(char* album);
char* getTitle();
char* getArtist();
char* getDuration();
char* getAlbum();
};
You haven't allocated any memory for strcpy to copy into. Thus your constructor invokes undefined behavior.
You need to allocate a character array first. But then you also need to deallocate it in each of your setters. Otherwise the memory will be leaked, since you're reassigning the pointer that manages it.