I have implemented the swap via function for two numbers and this works well. However, I am now trying to swap two character strings but i receive the names in the same order. Would anybody know where I am going wrong or what I could do to have the names change positions? here is an example of the code below:
#include "stdafx.h"
#include <cstring>
#include <iostream>
#include <string>
using namespace std;
void swapages (int &age1, int &age2);
void swapname(char *person1, char *person2);
int _tmain(int argc, _TCHAR*argv[])
{
char person1[] = "Alex";
char person2[] = "Toby";
int age1 = 22;
int age2 = 27;
cout << endl << "Person1 is called " << person1;
cout << " and is " << age1 << " years old." << endl;
cout << "Person2 is called " << person2;
cout << " and is " << age2 << " years old." << endl;
swapname(person1,person2);
swapages(age1,age2);
cout << endl << "Swap names..." << endl;
cout << endl << "Person1 is now called " << person1;
cout << " and is " << age1 << " years old." << endl;
cout << "Person2 is now called " << person2;
cout << " and is " << age2 << " years old." << endl;
system("pause");
return 0;
}
void swapages(int &age1, int &age2)
{
int tmp = age2;
age2 = age1;
age1 = tmp;
}
void swapname(char *person1, char *person2)
{
char* temp = person2;
person2 = person1;
person1 = temp;
}
You have tagged this as C++, and you are including the <string> header already, so why not use std:string instead of all those pointers and arrays?
void swapname(string &person1, string &person2)
{
string temp(person2);
person2 = person1;
person1 = temp;
}
int _tmain(int argc, _TCHAR*argv[])
{
string person1 = "Alex";
string person2 = "Toby";
swapname(person1, person2);
}
The problem is that you are trying to swap pointers that are local variables of the function while you need to swap strings. So you need to copy one string into another string. Moreover the strings can have different lengths so the exact swap will be impossible. It could be done without problems if the parameters of the function would be arrays (references to arrays) of the same size. For example
void swap_name( char ( &lhs )[5], char ( &rhs )[5] )
{
char tmp[5];
std::strcpy( tmp, lhs );
std::strcpy( lhs, rhs );
std::strcpy( rhs, tmp );
}
You need to make minor changes to get it to work the way you want it to work.
void swapname(char **person1, char **person2);
.
.
char *person1 = "Alex";
char *person2 = "Toby";
.
.
swapname(&person1, &person2);
.
.
and
void swapname(char **person1, char **person2)
{
char* temp = *person2;
*person2 = *person1;
*person1 = temp;
}
In your code, person1 and person2 are defined as 2 char arrays not char pointer variables, you can not swap them, if you pass the 2 arrays into the swapname function which takes 2 pointers as parameters, it should not even compile.
Related
So i have problem Im making class. In this class im supposed to have array of some data. I have no problem with assigning and creating new data with for example x2.NewAccount("123456" , 1000); this works fine the problem is when im trying to create data with string that is addressed to some variable. I know something about deep copying but I have no clue how to programm = operator in my case + i thought that strcpy but thats not working aswell.
PS: Its a school program so please dont judge me for not using headers and using bunch of includes that Im not using in code. Its made by my school and Im not allowed to change them + add them (I know that with string from c++ it would be much easier.).
Thanks for any help.
#ifndef __PROGTEST__
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cassert>
#include <cctype>
#include <cmath>
#include <iostream>
#include <iomanip>
#include <sstream>
using namespace std;
#endif /* __PROGTEST__ */
struct data_history{
int money = 0;
bool Income;
const char * UnStr;
const char * to_from;
};
struct client{
const char * accID;
int Balance;
int def_bal;
data_history * history;
int in_index = 0;
int in_cap = 10;
friend ostream &operator << (ostream &output , client p){
output << p.accID << ":" << endl << " " << p.def_bal << endl;
for (int i = 0 ; i < p.in_index ; i++){
if (p.history[i].Income == false)
output << " - " << abs(p.history[i].money) << ", to: " << p.history[i].to_from << ", sign: " << p.history[i].UnStr << endl;
else
output << " + " <<abs(p.history[i].money) << ", from: " << p.history[i].to_from << ", sign: " << p.history[i].UnStr << endl;
}
output << " = " << p.Balance << endl;
return output;
}
};
class CBank
{
public:
int cap = 10;
int index = 0;
client * database;
~CBank(){
for (int i = 0 ; i < index ; i++)
delete[] database[i].history;
delete[]database;
}
CBank(){
database = new client[cap];
}
bool NewAccount ( const char * accID, int initialBalance ){
for(int i = 0 ; i < index ; i ++)
if (accID == database[i].accID) {
return false;
}
//strcpy (database[index].accID , accID ); // Im getting errors while compileing (cuz I was using const char * for database.accID when i chenged it i got program crash.
database[index].accID = accID;
database[index].Balance = initialBalance;
database[index].def_bal = initialBalance;
database[index].in_cap = 10;
database[index].history = new data_history[database[index].in_cap];
index ++;
return true;
}
client Account (const char * accID ){
const char * input =accID;
for (int i = 0 ; i < index ; i++){
if (database[i].accID == input )
return database[i];
}
throw "error";
}
void print (){
for (int i = 0 ; i < index ; i ++) {
cout << endl;
cout << i << " = "<< " ID = " << database[i].accID << " | Balance = " << database[i].Balance << endl;
cout << "===Account history ===\n\n";
for (int y = 0 ; y < database[i].in_index; y++) {
cout << "Was it for him? : " << boolalpha << database[i].history[y].Income
<< "\nHow much : " << database[i].history[y].money << "\nUnique string : "
<< database[i].history[y].UnStr << "\nfrom/to: " << database[i].history[y].to_from << endl << endl;
}
}
}
private:
};
#ifndef __PROGTEST__
int main ( void )
{
char accCpy[100], debCpy[100], credCpy[100], signCpy[100];
CBank x2;
strncpy ( accCpy, "123456", sizeof ( accCpy ) );
assert ( x2 . NewAccount ( accCpy, 1000 ) );
x2 . print();
cout << "\n\n\n\n";
strncpy ( accCpy, "987654", sizeof ( accCpy ) );
assert ( x2 . NewAccount ( "987654", -500 ) );
x2 . print();
}
#endif /* __PROGTEST__ */
When using database[index].accID = accID; you are only doing a shallow copy (and relying on the caller to keep this memory valid as the pointer may be accessed).
You've correctly identified that you need to preform a deep-copy, but client::accID is just a pointer, but you may not copy into it until you initialize it to point to some memory.
One way of doing this is to dynamically allocate and manage client::accID similar to how you are dynamically allocating and managing client::history.
Instead of strcpy (database[index].accID , accID ); or database[index].accID = accID;, try:
size_t bufsize = strlen(accID) + 1;
char *buf = new char[bufsize];
memcpy(buf, accID, bufsize);
database[index].accID = buf;
and in the destructor add:
delete[] database[i].accID
As others have pointed out, this style of C++ programing is very error prone and not looked upon well by the community. This manually memory management can be easily avoided by using the standard library classes. Even after making the changes above, your program will run into undefined behavior if you start copying CBank objects.
Even if you don't have to for your assignment, you should consider trying to rewrite this as an exercise with:
std::string instead of C-strings for accID;
std::vector instead of the data_history array
Also FYI:
if (database[i].accID == input )
Will not do what expect with c-strings...
Take this question when i read a program (quote:c++ primer plus) 4.22 and make some change in it
#include <iostream>
#include <cstring>
using namespace std;
char * getName();
int main(int argc, const char * argv[]) {
// insert code here...
char *name;
name = getName();
string sb = name;
cout << name << " at " << (int *)name << "\n";
cout << *name << " " << sb << endl;
cout << &sb << endl;
delete [] name;
name = getName();
sb = name;
cout << name << " at " << (int *) name << "\n";
cout << *name << " " << sb << endl;
cout << &sb << endl;
delete [] name;
cout << sb << endl;
cout << &sb << endl;
return 0;
}
char *getName()
{
char temp[80];
cout << "Enter last name: ";
cin >> temp;
char *pn = new char[strlen(temp) + 1];
strcpy(pn, temp);
return pn;
}
and there have no memory leak.
i check sb's address is different from name.
i think may it work like this
std::string
first step : malloc (char *, sizeof(char *) * sizeof(name) )
then : snprintf( string , sizeof (string) , "%s", name)
final : string get a new address
if i use a statement:
string = string + " am i a pointer";
it still work.
i guess it is really a pointer!
just realloc it
hereby, i think string is kind of char* or char array, i try to *string then the compiler tell me something wrong with it! i can't use like this, so i hope someone can explain what type of string is in compiler and how it work! why string is not a pointer? or it's actually a pointer but it have special method to use?
tip:All work on mac os
i hope someone can explain what type of string is
It is a class.
why string is not a pointer? or it's actually a pointer but it have special method to use?
It's not a pointer. A pointer couldn't store the necessary data to fulfill the requirements defined by the standard.
i think string is kind of char* or char array
It's not. However, it quite probably does have a char pointer to an array as a data member.
I have a program with one structnamed sample, it contains 2 int members and one char *. when creating 2 objects called a and b, I try assign a new dynamic string to a with the pointer and then copy all the values to b. so b = a. But later on when try to make changes to a like this : a.ptr[1] = 'X'; the pointer in b also changes. I want to know why, and how can I solve this.
struct Sample{
int one;
int two;
char* sPtr = nullptr;
};
int _tmain(int argc, _TCHAR* argv[])
{
Sample a;
Sample b;
char *s = "Hello, World";
a.sPtr = new char[strlen(s) + 1];
strcpy_s(a.sPtr, strlen(s) + 1, s);
a.one = 1;
a.two = 2;
b.one = b.two = 9999;
b = a;
cout << "After assigning a to b:" << endl;
cout << "b=(" << b.one << "," << b.two << "," << b.sPtr << ")" << endl << endl;
a.sPtr[1] = 'X' ;
cout << "After changing sPtr[1] with 'x', b also changed value : " << endl;
cout << "a=(" << a.one << "," << a.two << "," << a.sPtr << ")" << endl;
cout << "b=(" << b.one << "," << b.two << "," << b.sPtr << ")" << endl;
cout << endl << "testing adresses for a and b: " << &a.sPtr << " & b is: " << &b.sPtr << endl;
return 0;
}
Your struct contains a char*. When you assign all values in a to b, the pointer is also copied.
This means that a and b now point to the same char array. Therefore changing a value in this char array changes it for both structs.
If you do not want this, make a new char array for b and use strcpy.
You are copying the pointer not the value. To solve this you could override your assignment operator in the structure:
struct Sample{
int one;
int two;
char* sPtr = nullptr;
Sample& operator=(const Sample& inputSample)
{
one = inputSample.one;
two = inputSample.two;
sPtr = new char[strlen(inputSample.sPtr) + 1];
strcpy (sPtr, inputSample.sPtr);
return *this;
}
};
For the life of me I can't figure out why the I can't write to a c style string inside of a struct.
College student - can't use string class, haven't learned pointers.
Help? 2 hours at trying to figure this out.
#include <iostream>
using namespace std;
void strCopy(char from[], char to[])
{
for (int i = 0; i < 255; i++)
{
to[i] = from[i];
}
}
struct card
{
char suit[20];
char rank[20];
int cvalue;
char location[20];
};
void printCard(card card)
{
cout << card.rank << " of " << card.suit << endl;
}
int main()
{
// I don't think strCopy()'s the problem, I've used it with my last project.
cout << "Test strCopy()" << endl;
char str1[14] = "abcdefghijklm";
char str2[14];
strCopy(str1, str2);
cout << " " << str2 << endl << endl;
// Now the negative.
card one;
one.cvalue = 2;
strCopy("Somewhere", one.location);
strCopy("Two", one.rank);
strCopy("Hearts", one.suit);
printCard(one);
}
// I don't think strCopy()'s the problem, I've used it with my last
project.
Wrong
for (int i = 0; i < 255; i++)
{
to[i] = from[i];
}
copies 255 characters, however that's not what you meant.
If here :
strCopy(str1, str2);
cout << " " << str2 << endl << endl;
Your're getting "correct" output, then you're just unlucky, since that invokes an undefined behavior, an you're writing off the end of the array.
I'm trying to read names and ages from user, until user inputs "stop". Then just print all these values. Please help me , I'm just the beginner in C++
// Pass.cpp
// Reading names and ages from user and outputting them
#include <iostream>
#include <iomanip>
#include <cstring>
using std::cout;
using std::cin;
using std::endl;
using std::setw;
using std::strcmp;
char** larger(char** arr);
int* larger(int* arr);
void read_data(char*** names, int** ages);
void print_data(char*** names, int** ages);
int main()
{
char** names = new char*[5];
char*** p_names = &names;
int* ages = new int[5];
int** p_ages = &ages;
read_data(p_names,p_ages);
print_data(p_names,p_ages);
}
void read_data(char*** names, int** ages)
{
const char* sent = "stop";
const int MAX = 15;
int count = 0;
char UI[MAX];
cout << "Enter names and ages."
<< endl << "Maximum length of name is " << MAX
<< endl << "When stop enter \"" << sent << "\".";
while (true)
{
cout << endl << "Name: ";
cin.getline(UI,MAX,'\n');
if (!strcmp(UI, sent))
break;
if (count + 1 > sizeof (&ages) / sizeof (&ages[0]))
{
*names = larger(*names);
*ages = larger(*ages);
}
*names[count] = UI;
cout << endl << "Age: ";
cin >> *ages[count++];
}
}
void print_data(char*** names, int** ages)
{
for (int i = 0; i < sizeof(*ages) / sizeof(*ages[0]);i++)
{
cout << endl << setw(10) << "Name: " << *names[i]
<< setw(10) << "Age: " << *ages[i];
}
}
char** larger(char** names)
{
const int size = sizeof(names) / sizeof(*names);
char** new_arr = new char*[2*size];
for (int i = 0; i < size; i++)
new_arr[i] = names[i];
return new_arr;
}
int* larger(int* ages)
{
const int size = sizeof(ages) / sizeof(*ages);
int* new_arr = new int[2 * size];
for (int i = 0; i < size; i++)
new_arr[i] = ages[i];
return new_arr;
}
You are really over complicating things.
Given the original problem:
Write a program that reads a number (an integer) and a name (less than
15 characters) from the keyboard. Design the program so that the data
is done in one function, and the output in another. Store the data in
the main() function. The program should end when zero is entered for
the number. Think about how you are going to pass the data between
functions
The problem wants you to think about passing parameters to functions. A simple solution would be:
#include "stdafx.h"
#include <iostream>
#include <iomanip>
using namespace std;
// Pass in a char array and an integer reference.
// These values will be modified in the function
void read_data(char name[], int& age)
{
cout << endl << "Age: ";
cin >> age;
cin.ignore();
cout << endl << "Name: ";
cin.getline(name, 16);
}
// Pass a const array and an int value
// These values will not be modified
void print_data(char const *name, int age)
{
cout << endl << setw(10) << "Name: " << name
<< setw(10) << "Age: " << age;
}
int main()
{
char name[16];
int age;
cout << "Enter names and ages."
<< endl << "Enter 0 age to quit.";
do {
read_data(name, age);
print_data(name, age);
} while (0 != age)
}
EDIT: Modified per user3290289's comment
EDIT2: Storing data in an array
// Simplify by storing data in a struct (so we don't have to manage 2 arrays)
struct Person {
char name[16];
int age;
};
// Returns how many People were input
int read_data(Person*& arr)
{
int block = 10; // How many persons to allocate at a time
arr = NULL;
int arr_size = 0;
int index = 0;
while (true) {
if (index == arr_size) {
arr_size += block;
arr = (Person *)realloc(arr, arr_size * sizeof(Person)); // Reallocation
// Should check for error here!
}
cout << endl << "Age: ";
cin >> arr[index].age;
cin.ignore();
if (0 == arr[index].age) {
return index;
}
cout << endl << "Name: ";
cin.getline(arr[index++].name, 16);
}
}
void print_data(Person *arr, int count)
{
for (int i = 0; i < count; i++) {
cout << endl << setw(10) << "Name: " << arr[i].name
<< setw(10) << "Age: " << arr[i].age;
}
}
int main()
{
Person *arr;
int count = read_data(arr);
print_data(arr, count);
free(arr); // Free the memory
}
try this:
#include <iostream>
#include <iomanip>
#include <vector>
#include <sstream>
using std::cout;
using std::cin;
using std::endl;
using std::setw;
using std::strcmp;
void read_data(std::vector<std::string> &names, std::vector<int> &ages);
void print_data(std::vector<std::string> &names, std::vector<int> &ages);
int main()
{
std::vector<std::string> names;
std::vector<int> ages;
read_data(names, ages);
print_data(names, ages);
}
void read_data(std::vector<std::string> &names, std::vector<int> &ages)
{
const char* sent = "stop";
cout << "Enter names and ages."
<< endl << "When stop enter \"" << sent << "\".";
while (true)
{
std::string input;
cout << endl << "Name: ";
std::getline(cin, input);
if (!strcmp(input.c_str(), sent))
break;
names.push_back(input);
cout << endl << "Age: ";
std::string age;
std::getline(cin, age);
ages.push_back(atoi(age.c_str()));
}
}
void print_data(std::vector<std::string> &names, std::vector<int> &ages)
{
for (int i = 0; i < names.capacity() ; i++)
{
cout << endl << setw(10) << "Name: " << names.at(i)
<< setw(10) << "Age: " << ages.at(i);
}
}
One problem I see is this if statement:
if (count + 1 > sizeof (&ages) / sizeof (&ages[0]))
&ages is the address of an int**, a pointer, and so it's size is 8 (usually) as that is the size of a pointer type. The function does not know the size of the array, sizeof will only return the correct answer when ages is declared in the same scope.
sizeof(&ages) / sizeof(&ages[0])
will always return 1
I believe one natural solution about this problem is as follows:
create a "std::map" instance. Here std::map would sort the elements according to the age. Here my assumption is after storing the data into the container, you would like to find about a particular student age/smallest/largest and all various manipulation with data.Just storing and printing the data does not make much sense in general.
create a "std::pair" and take the both input from the user into the std::pair "first" and "second" member respectively. Now you can insert this "std::pair" instance value into the above "std::map" object.
While printing, you can now fetch the each element of "std::map" in the form of "std::pair" and then you can display pair "first" and "second" part respectively.