Error: "uninitialsed local variable 'name' used" in C++ using char * - c++

I have written this code snippet:
int main()
{
char *name;
cin >> name;
return 0;
}
After compiling it gives error as: "uninitialsed local variable 'name' used". I don't understand why this is happening. Please explain what is my problem.
Thanks.

char* is a pointer to a char which, at the moment, doesn't 'point' anywhere. You could allocate some memory and point to that.
char* name = new char[64];
cin >> name;
delete[] name;
However, you can avoid this requirement by using std::string. Have a look at some examples here: http://www.cplusplus.com/forum/articles/6046/

Unless you allocate memory for name you are writing to an uninitialized pointer.
Try this:
#include <iostream>
int main()
{
char *name = new char[100];
std::cin >> name;
delete [] name;
return 0;
}

Related

C++ memcpy/strcpy of char pointer to class member char pointer

i have a custom class, let's call it "Student" and a main method. I'm instanciating the class, and just want to output the content of the class.
My programm crashes with a: Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)
Actual Code
Student.h
#ifndef PROG2_STUDENT_H
#define PROG2_STUDENT_H
#include <iostream>
class Student
{
private:
char *name;
char *firstName;
unsigned matriculationNumber;
unsigned semester;
public:
Student(char *name, char *firstName, unsigned matriculationNumber, unsigned semester);
~Student();
friend std::ostream &operator<<(std::ostream &ostream, const Student &student);
private:
};
#endif
Student.cpp
#include <cstring>
#include "Student.h"
Student::Student(char *name, char *firstName, unsigned matriculationNumber, unsigned semester)
{
std::strcpy(this->name, name);
std::strcpy(this->firstName, firstName);
this->matriculationNumber = matriculationNumber;
this->semester = semester;
}
Student::~Student()
{
delete[] this->name;
delete[] this->firstName;
}
std::ostream &operator<<(std::ostream &stream, const Student &input)
{
stream << input.name << ", " << input.firstName << ": "
<< input.semester << " Semester, MA " << input.matriculationNumber;
return stream;
}
and my main
#include <iostream>
#include "StudentPackage/Collection/StudentCollection.h"
int main()
{
Student studentOne((char *)"Testerson", (char *)"Test", 12345, 2);
std::cout << studentOne << std::endl;
return 0;
}
What i have tried
I have tried several things, including memcpy. But with memcpy I'm not able to detect the size of the char array correctly.
When i change the Student Constructor to the following, i get problems with the delete/free in the destructor. I guess, this isn't the correct way anyway, but this is happening, because the scope of the input variables are destroyed before the class destructor is called, correct?
Student::Student(char *name, char *firstName, unsigned matriculationNumber, unsigned semester)
{
this->name = name;
this->firstName = firstName;
this->matriculationNumber = matriculationNumber;
this->semester = semester;
}
Question
How can i correctly copy the char array from constructor (name to this->name)?
How can i correctly copy the char array from constructor (firstName to this->firstName)?
std::strcpy does not allocate memory. So your program is copying input to a "garbage" address that is occurred in the memory area where your Student object is placed. And as result no surprise that you are getting segment violation as result. There are two solutions:
a "C-style" way - allocate memory manually (i.e. like auto n = std::strlen(name); this->name = new char[n + 1]; std::strcpy(this->name, name);), but then you need to delete it manually (i.e. delete name;) in the destructor. btw, n + 1 because you also need room for the null-terminator, strlen result does not include it.
much better and more "C++" way - use std::string (i.e. declate name member variable as std::string). Then you just can do an asignment: this->name = name;, and no need manual memory management - std::string will take care.
(Code style) Also recommend to use some prefix or postfix for member variables, i.e. like m_name(more "Microsoft" style), or name_ - more "Google" style, to avoid those unnecessary this->.

(C++ OOP) Why name[] is not changing when I assign its pointer to a new value?

I am new to C++ OOP concepts and I come from a Java OOP background. I have tried this->name=name but I get an error and then I tried to use a pointer, but, even though the code runs, it does not 'save' the name in the object's name.
#include <iostream>
using namespace std;
class Person{
private:
char name[];
int age;
public:
Person(char name[], int age){
char* pName=this->name;
pName=name;
this->age=age;
cout<<this->name;
}
getInformation(){
cout<<"name: "<<this->name<<" age: "<<this->age;
}
};
int main(){
Person foo("foo",5);
}
In C++, arrays usually need to be declared with a length - in this case, char name[] would be invalid.
Additionally, arrays declared int array[5] (with a size) cannot be directly assigned to. i.e. this is invalid:
class A
{
public:
int array[5];
void foo() {
int other_array[5] = {0, 0, 0, 0, 0};
this->array = other_array;
}
}
Instead, you need to assign each element one at a time (e.g. in a loop):
for(int i = 0; i < 5; ++i) this->array[i] = other_array[i];
This is because in C++ arrays have space for all the elements, unlike Java where char name[] is a pointer to an array. If you want to be able to directly change what array a variable refers to, you should use a pointer instead - a pointer can be dereferenced like an array:
class A
{
public:
int *array;
int foo(int *other_array) {
this->array = other_array;
}
}
Though if you do this, be careful of memory management.
Ignoring (for the moment) the fact that the code is invalid and won't compile; here:
char* pName=this->name;
You instantiate a local pointer and assign the unitialised pointer name to it. Then you immediately reassign it with a pointer to the parameter name:
pName=name;
But both pName and name are temporary and are pointers to strings, not the strings themselves. Moreover pName is not a reference to this->name. So on return from the Person() constructor, the object remains unchanged (and uninitialised). You may have intended:
char*& pName = this->name ;
pName = name ;
But that is simply a convoluted form of:
this->name = name ;
and is still ill advised because you are then assigning this->name with the address of the literal string "foo" from main() which is const. In any case you are giving Person a pointer to data that belongs to something else and is not "owned" by Person, and Person has no knowledge of the data's lifetime or validity. It is recipe for all kinds of bugs and undesired behaviour.
Null-terminated (or ASCIZ or C-style) strings are not a true data type; it is merely a char array convention. Moreover arrays even are not first-class data types in C++ and you cannot assign one array to another or pass an array by value as a function argument - instead assignment and argument passing are pointer operations. In Person(), name is a pointer to the first character in the string constant "foo" not an independent string containing "foo".
To correct this using C-style strings:
#include <iostream>
#include <cstring>
class Person
{
private:
char name[256]; // << Must have size here.
int age;
public:
Person( const char* name, int age) // << Must have const arg for "foo" to be a valid parameter.
{
std::strncpy( this->name, // << C strings must be explicitly copied, not "assigned".
name,
sizeof(this->age) - 1 ) ;
this->age = age;
}
void getInformation() const // << must have return type, and may be const.
{
std::cout << "name: " << this->name << " age: " << this->age << "\n" ;
}
} ;
However in most cases it would be preferable to use C++ std::string objects:
#include <iostream>
#include <string> // << Use C++ string library
// (i.e. string rather than cstring/string.h)
class Person
{
private:
std::string name; // << std::string memory management is intrinsic
int age;
public:
Person( const std::string name, int age)
{
this->name = name ; // << Assignment possible due to
// operator overloading
this->age = age;
}
void getInformation() const
{
std::cout << "name: " << this->name << " age: " << this->age << "\n" ;
}
} ;
As said above, std::string is to recommend for now.
Not only for this problem, std::string is very nice to work with in many cases. especially in the learningface.
Just take a look at the string class here from MS' site:
https://learn.microsoft.com/en-us/cpp/standard-library/basic-string-class?view=vs-2019
If you're using c++, it's way better to use std::string to deal with strings.
But answring to your question, when you assign a value to any variable, it overrides its previous value and gets a new one.
In your code:
char* pName=this->name;
pName=name;
The first line assigns a new value to your pName variable. and the second line, simply overrides your first line, and copies something new into your pName variable. so, that's not a correct approach for what you want to do.
If you want to have a char * variable and copy content of another char * into it, I suggest something like:
private:
char *name;
...
public:
Person(char name[], int age){
this->name = strdup(name);
...
}
And be careful to free memory of name in your destructor function.

Pointer to a structure in an array of structures

So i need to get code of the structure#1 (e[0]) but i get the following error;
"error: request for member 'get_code' in 'emp1', which is of pointer type 'Employee*' (maybe you meant to use '->' ?)"
i don't really understand how to fix this. Plus, it's an assigment so i'm bound to use structures,and also, i don't know what "->" is, but if it's any operator or something, im not allowed to use it cause we haven't been taught that yet.
(Answers to the similar question suggest using -> so that doesnt work for me.)
i also tried using *(emp1).get_code()
#include <iostream>
#include <string.h>
using namespace std;
struct Employee{
private:
string code;
string name;
float salary;
public:
void set_code(string c){
code=c;
}
void set_name(string n){
name=n;
}
void set_sal(float s){
salary=s;
}
string get_code(){
return code;
}
string get_name(){
return name;
}
float get_sal(){
return salary;
}
};
int main(void) {
Employee e[2],*emp1,*emp2;
string c,n;
float s;
for (int i=0;i<2;i++){
cout<<"Enter code for employee "<<i+1;
cin>>c;
e[i].set_code(c);
cout<<"Enter name for employee "<<i+1;
cin>>n;
e[i].set_name(n);
cout<<"Enter salary for employee "<<i+1;
cin>>s;
e[i].set_sal(s);
}
*emp1=e[0];
cout<<emp1.get_code();
}
First of all, this line is not correct:
*emp1=e[0];
What your line does is assign the structure value 'e[0]' to the structure at pointer 'emp1'. However, the pointer 'emp1' is never initialized, so you'd end up writing in an invalid location.
What you need to write is:
emp1=&e[0];
That will actually set emp1 to the location of 'e[0]'.
Secondly, the symbol '->' is what you use when you want to access a member of a pointer.
In this case you should not write:
cout<<emp1.get_code();
But rather:
cout<<emp1->get_code();
The reason why you need to write that is that 'emp1' is a pointer. Thus, to access its member 'get_code', you need to use the symbol '->'.

Trying to delete string from memory. Won't let me assign to cin

#include "stdafx.h"
#include "Cfriend.h"
int _tmain(int argc, _TCHAR* argv[])
{
std::string * TempName = new std::string;
std::cout << "Name your friend:\n";
std::getline (std::cin, TempName);
Cfriend * MyFriend = new Cfriend();
return 0;
}
Hi, I'm new around here. I'm trying to create a simple procedure where the player can assign a name to Cfriend, but the problem is that it won't let me assign cin to TempName.
I want to be able to delete TempName from memory as soon as I'm done with it.
The problem is you're trying to use a std::string* where a std::string is expected.
The best solution is to not use new to create every object, C++ is not Java or C#.
#include "Cfriend.h"
int main(int argc, char* argv[])
{
std::string tempName;
std::cout << "Name your friend:\n";
std::getline (std::cin, tempName);
Cfriend myFriend;
return 0;
}
I want to be able to delete TempName from memory as soon as I'm done with it.
Why? Is the name going to be thousands of bytes long?
If it's essential that it be destroyed then let the std::string destructor do that:
#include "Cfriend.h"
int main(int argc, char* argv[])
{
Cfriend myFriend;
{
std::string tempName;
std::cout << "Name your friend:\n";
std::getline (std::cin, tempName);
myFriend.setName(tempName);
}
return 0;
}
tempName goes out of scope at the closing brace and its memory is deallocated.
If you really, really can't re-arrange the code like this, you can still force the string to deallocate the memory it owns:
std::string tempName;
// ...
tempName.clear();
tempName.shrink_to_fit();
When every single commenter is telling you to stop using new explicitly that should be a pretty big hint to re-evaluate your assumptions about writing good C++.
As for the destruction of TempString, it will be destructed once it leaves the scope.
that means you can write e.g.
int main()
{
// Some code...
{
std::string temp;
std::getline(std::cin, temp);
// Do something with the string `temp`
}
// No `temp` string object, it doesn't exist, and has been destructed
// More code...
}
The big question here, though, is why you would want this? Unless you expect several megabytes of input text in a single line, there is really no use of scoping for temporary variables. And if you want to redeclare the temp (or TempString) variable, why would you do that? Just reuse the existing variable.
TempName there is a pointer to a string. Try adding a * before it for dereferencing when using it:
getline(std::cin, *TempName);
Or you can also just use a string in advance and not a pointer to it:
int main()
{
std::string myString;
std::getline(std::cin, myString);
// Do something with the string you just read
}

Why does this give a bad_alloc error?

Currently I'm trying to set up a member function for Student that reads a string from cin, is used as an argument for this function and then creates a Student object with the data. However, is it giving me a bad_alloc error. I know the function is getting the string but it gives this error after the new object is created.
Error:
./a.out
Please insert name for student:
Bob_Russel
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
Aborted
Constructor:
Student::Student(string tname){
name = tname;
}
Function:
Student Student::readStudent(istream &i){
Student *stud;
string y;
i >> y;
stud = new Student(y);
return *stud;
}
testStudent.cpp:
#include "Student.h"
int main(){
Student *stud3;
cout << "\nPlease insert name for student:\n";
stud3->readStudent(cin);
return 0;
}
Not only does the code leak memory (creating a new Student in readStudent that is never deleted), in main you are using an uninitialized pointer to call readStudent. Possibly this is corrupting your heap such that the call to new throws a std::bad_alloc.
Take another look at C++ memory management and object lifetimes. There is really no need to use pointers at all here. As a starting point, your main could be modified to this:
int main() {
Student stud3;
std::cout << "Please insert name for student:" << std::endl;
stud3.readStudent(std::cin);
}
It would perhaps also be better if you read in the name within main (as a std::string), and then pass the name directly to the Student constructor:
int main() {
std::cout << "Please insert name for student:" << std::endl;
// Read in the name.
std::string name;
std::cin >> name;
// Create the student with the input name.
Student stud3(name);
}
It looks like you're trying to implement a factory method. If that's the case, then you're missing the static keyword and the correct syntax for the readStudent call.
class Student{
public:
Student(std::string tname);
static Student* readStudent(std::istream &i);
private:
std::string name
};
Student::Student(std::string tname) {
name = tname;
}
Student* Student::readStudent(std::istream &i){
std::string y;
i >> y;
return new Student(y);
}
int main(int argc, char* argv[]){
Student *stud3 = NULL;
std::cout << "\nPlease insert name for student:\n";
stud3 = Student::readStudent(cin);
return 0;
}
You are allocating on the heap using new and never freeing it, thus you run out of memory and get a bad_alloc. For every new there should be a delete.
This will not throw bad_alloc:
Student Student::readStudent(std::istream& i)
{
std::string y;
i >> y;
return Student(y);
}