I am learning the basics of C++. The code is working fine as I wanted, but what I want to know is in case 2 where the function is to swap the strings, what is basically going on? Is the string at array[pos1 -1] being copied to temp and then swapped or just the addresses of the strings to be swapped are being reallocated?
#include <iostream>
using namespace std;
int main()
{
const char *array[] {"Albert",
"Newton",
"Gallilio",
"Hawking"};
cout << "What do you want to do:\n1-Display Strings\n2-Swap Positions" << endl;
unsigned short int choice{};
cin >> choice;
switch (choice)
{
case 1:
{
for (short int i = 0; i < _countof(array); i++)
{
cout << "\n" << array[i];
}
cout << endl;
break;
}
case 2:
{
short int pos1{}, pos2{};
const char *temp{ nullptr };
cout << "Whom do you want to swap? Enter two numbers when prompted: " << endl;
cout << "Swap --- "; cin >> pos1;
cout << "With --- "; cin >> pos2;
temp = array[pos1 - 1];
array[pos1 - 1] = array[pos2 - 1];
array[pos2 - 1] = temp;
cout << "\nChanged Order is";
for (short int i{} ; i < _countof(array); i++)
{
cout << "\n" << array[i];
}
cout << endl;
break;
}
default:
cout << "\a";
}
return 0;
}
Let's assume pos1 is 1 and pos2 is 2.
Then array[pos1-1] holds a pointer to a character A that is interpreted as a string of characters Albert\0 terminated by a null. Likewise array[pos2-1] holds a pointer to the string Newton\0.
When case 2 is hit, temp is initialized to hold a null pointer. Then temp is assigned to hold a copy of the pointer to Albert\0. Then array[pos1-1] is reassigned to hold a pointer to Newton\0. We then want array[pos2-1] to point to Albert\0, but the pointer value in array[pos1-1] doens't point there anymore. That's where the copy in temp comes in, because it is still a pointer to Albert\0, so this pointer is copied to array[pos2-1].
Related
Hi I want to create a 2d growing dynamic array with use of char. The problem is that my function put all word in the same row. The dynamic allocation is not good but I don't know how to correct this.
void display(char** data, int length)
{
for (int i = 0; i < length; i++)
for (int j = 0; j < data[i][j] != '\0'; j++)
cout << data[i][j];
cout << endl;
}
void add(char** &data, int length, char* word)
{
if (length == 1)
{
data = new char* [length];
}
data[length-1] = new char[strlen(word)+1];
strcpy_s(*(data + length -1), strlen(word) + 1, word);
data[length - 1][strlen(word) + 1] = '\0';
}
int main()
{
char** data = NULL;
int choice = 0, length = 0; char name[80];
cout << "Enter your choice" << endl;
while (cin >> choice && choice != 3)
{
switch (choice)
{
case 0:
cout << "Enter name to add: " << endl;
cin.ignore(); cin.getline(name, 80);
length++;
add(data, length, name);
break;
}
cout << endl << "Enter your next choice: " << endl;
}
This is what is get
Enter your choice
0
Enter name to add:
jhon
jhon
Enter your next choice:
0
Enter name to add:
marc
jhonmarc
I'm pretty sure that instead of
if (length = 1)
you meant to write
if (length == 1)
In C++ = means assignment and == means equality.
Seems your code has other bugs though. You never grow the size of data. Do it the easy way and use std::vector<std::string>
#include <vector>
#include <string>
int main()
{
std::vector<std::string> data;
int choice = 0, length = 0; std::string name;
cout << "Enter your choice" << endl;
while (cin >> choice && choice != 3)
{
switch (choice)
{
case 0:
cout << "Enter name to add: " << endl;
cin.ignore(); getline(cin, name); // read name
data.push_back(name); // add name to data
break;
}
cout << endl << "Enter your next choice: " << endl;
}
Problem solved.
So currently I am still confused in using pointers and reference and I do not know if what I am doing is right. My program is a calculator that stores everything the user inputs. There is an option that the user will be asked if he/she want to view the history and if he/she wants it the program will show all the data he/she inputs.And I need to use pointers and reference in my program but I am still confused on how to use pointers and reference into array
Here is my initialization:
int main() {
int size = 1, fNum[size], sNum[size];
char oprtn[size], answer;
;
float result[size];
int *ptrf = &fNum[size];
int *ptrs = &sNum[size];
char *ptro = &oprtn[size];
float *ptrRes = &result[size];
while (true) {
cout << "=====CALCULATOR=====\n\n";
cout << "ENTER TWO NUMBERS:" << endl;
while (!(cin >> *ptrf >> *ptrs)) {
system("cls");
cout << "INVALID INPUT. PLEASE ENTER TWO NUMBERS:\n";
cin.clear();
cin.ignore(2);
}
cout << endl;
do {
cout << "Choose Operation to be Used: \n"
<< " + --- Addition \n"
<< " - --- Subtraction \n"
<< " * --- Multiplication \n"
<< " / --- Division \n"
<< " % --- Remainder \n";
cout << "Answer: ";
cin >> answer;
cout << endl;
switch (answer) {
case '+':
cout << "ADDITION\n";
break;
case '-':
cout << "SUBTRACTION\n";
break;
case '*':
cout << "MULTIPLICATION\n";
break;
case '/':
cout << "DIVISION\n";
break;
case '%':
cout << "REMAINDER\n";
break;
default:
answer = false;
system("cls");
cout << "PLEASE ENTER A VALID ANSWER. CHOOSE BELOW.\n\n";
cout << "FIRST NUMBER: " << *ptrf << endl;
cout << "SECOND NUMBER: " << *ptrs;
cout << endl << endl;
continue;
}
} while (!answer);
cout << "DO YOU WANT TO TRY AGAIN? (Y / N): ";
cin >> answer;
switch (answer) {
case 'Y':
case 'y':
system("cls");
continue;
default:
cout << "VIEW HISTORY? (Y / N): ";
cin >> answer;
switch (answer) {
case 'Y':
case 'y':
cout << "HISTORY\n\n";
break;
default:
return 0;
}
}
}
}
This is not valid C++ code:
int size = 1, fNum[size], sNum[size]; // wrong: C++ forbids Variable Length Arrays (1)
char oprtn[size], answer; // ditto...
;
float result[size]; // ditto...
int *ptrf = &fNum[size]; // wrong: this syntax makes ptrf points one past end of array (2)
int *ptrs = &sNum[size]; // ditto...
char *ptro = &oprtn[size]; // ditto...
(1): VLA are a C language concept. Some compilers (gcc and CLang) allow it as an extension but it is useless in C++ because of the containers from the standard library
(2): the idiomatic way to initialize a pointer to the beginning of an array is just int *ptrf = Num; When used as a rvalue (in short at the right side of an = sign), an array decays to a pointer to its first element. So it reads (int *) ptr = &(fNum[0]);: ptr is a pointer to int and its initial value is the address of the first element of the array fNum
fNum[size]
is an array of one integer.
int *ptrf = &fNum[size];
Is a pointer to one past the last element of this array, therefore it's out of bounds access, this is undefined behaviour.
Since it only has one element, you declaring it as an array is pointless.
A pointer to the beginning of an array would be:
int *ptrf = fNum;
Or
int *ptrf = &fNum[0];
You can then cycle trough the array incrementing the pointer ptrf++.
To assing a pointer to a variable:
int x;
int *ptr = &x;
So the variable declarations and assignments:
int size = 1, fNum[size], sNum[size];
char oprtn[size], answer;
float result[size];
int *ptrf = &fNum[size];
int *ptrs = &sNum[size];
char *ptro = &oprtn[size];
float *ptrRes = &result[size];
Are the same as:
int fNum, sNum;
char oprtn, answer;;
float result;
int *ptrf = &fNum;
int *ptrs = &sNum;
char *ptro = &oprtn;
float *ptrRes = &result;
That said, C++ has mutch nicer data containers you can use like std::vector or std::array.
One last note, variable length arrays(fNum[size]) are forbidden in C++.
Had this program in C and was trying to convert some to C++ as I learn the language. Basically char arrays to strings and some of the input/output. Only issue is I get a segfault when attempting to put the input string into the string array (test2 prints. test3 does not).
Any ideas? Any bad coding habits I should be aware of as I learn c++?
int main() {
int nstr=0, nchar=0, nint=0, nfloat=0;
string input;
int i, z=0;
float inputFloat;
string *strList = (string*)malloc(sizeof(string) * nstr);
char *charList = (char*)malloc(sizeof(char) * nchar);
int *intList = (int*)malloc(sizeof(int) * nint);
float *floatList = (float*)malloc(sizeof(float) * nfloat);
while (z != -42) {
cout << "Input: ";
cin >> input;
cin.ignore();
inputFloat = strtof(input.c_str(), NULL);
if (inputFloat) {
if (fmod(inputFloat, 1.0)) {
nfloat++;
floatList = (float*)realloc(floatList, sizeof(float) * nfloat);
floatList[nfloat-1] = inputFloat;
}
else {
nint++;
intList = (int*)realloc(intList, sizeof(int) * nint);
intList[nint-1] = (int)inputFloat;
}
}
else {
if (input.length() == 1) {
nchar++;
charList = (char*)realloc(charList, sizeof(char) * nchar);
if (input.at(0) == 10)
input = " ";
charList[nchar-1] = input.at(0);
}
else {
nstr++;
cout << "test1" << endl;
strList = (string*)realloc(strList, sizeof(string) * nstr);
cout << "test2" << endl;
strList[nstr-1] = input;
cout << "test3" << endl;
}
}
cout << "Integers: ";
for (i=0; i<nint; i++)
cout << intList[i] << " ";
cout << endl << " Floats: ";
for (i=0; i<nfloat; i++)
cout << floatList[i] << " ";
cout << endl << " Chars: ";
for (i=0; i<nchar; i++)
cout << charList[i] << " ";
cout << endl << " Strings: ";
for (i=0; i<nstr; i++)
cout << strList[i] << " ";
cout << endl << endl;
}
}
As a rule you don't use malloc,calloc,realloc etc. in c++ at all, even though you can.
It less meaningful for simple items like: int, char etc. but when using on objects (like std::string) it cause this kind of problems:
When this line runs:
string *strList = (string*)malloc(sizeof(string) * nstr);
You allocate storage to array of strings, but you didn't called any constructor, therefor all the storage you've allocated is still useless.
In c++ you must use new like this:
string *strList = new string[nstr];
it is shorter, easier and call the constructor of each allocated object.
In the end you dealocate it with delete [] like this:
delete [] strList;
Even better is to use:
vector<string> strList;
and add elements by using:
strList.push_back("something"); or strList.push_back(some_string);
vectors are take care for the memory allocation and free, and are freed automatically as regular object at end of life, so it won't needed to be deleted at all.
realloc reassigns a larger array than the previous one. The new element at the end of the array, you fill it as a integer, float, char , which are basic C types. For C++ objects like strings, the last element in your array is not a new string, one of the possibilities is to create arrays of string pointers.
at the start of your code
string **strList = (string**)malloc(sizeof(string *) * nstr);
and by the end of your code, allocate a new string object at the end of the array.
nstr++;
strList = (string**)realloc(strList, sizeof(string *) * nstr);
strList[nstr-1] = new string(input);
at the end of the program you must delete everything you created through new operator and thru malloc/realloc.
while (nstr--)
{
delete strList[nstr];
}
free(strList);
I'm a C++ newbie, I'm trying to put in practice pointers with strings. The program I have made is just to store strings the user types in the command line. But I'm getting segfault, not sure why.
This is the code:
#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;
//This code is meant to learn how to use pointers and strings
//Ask the user for who are they in the family and save it in string array!
void print_string (string* Value, int const nSize);
int get_names(string* Family_input);
int main ( int nNumberofArgs, char* pszArgs[])
{
cout << "Tis program stores your family members\n";
cout<< "Type the names and write 0 to exit\n";
string familia_string;
string* familia = &familia_string;
int family_number;
family_number=get_names(familia);
cout << "The family members are: ";
print_string(familia, family_number);
cout << endl;
return 0;
}
int get_names(string* Family_input)
{
int i=0;
string input="";
string old_input="";
while (input!="0")
{
cout << "type " << i <<" member\n";
//cin >> *(Family_input+i);
//input=*(Family_input+i);
cin >> input;
*(Family_input + old_input.length()) = input;
old_input=input;
i++;
}
return i;
}
void print_string (string* Value, int const nSize)
{// I don't want to &psValue to be changed!
for (int i=0; i<nSize; i++)
{
cout << *(Value+i) << " ";
//&psValue++;
}
}
I'm not sure if it's because I'm not taking correctly the size of the string, or I'm not using correctly the pointer or is that I have to allocate memory before using the offset.
As #kleszcz pointed out already, the line
*(Family_input + old_input.length()) = input;
is wrong. You are accessing memory that you are not supposed to.
The easiest fix is to change get_names slightly:
int get_names(string* Family_input)
{
int i=0;
string input="";
while (input!="0")
{
cout << "type " << i <<" member\n";
cin >> input;
*Family_input += input; // Just keep on appending to the input argument.
*Family_input += "\n"; // Add a newline to separate the inputs.
i++;
}
return i;
}
Also change print_string to:
void print_string (string* Value)
{
cout << *Value;
}
Of course, print_string has become so simple, you don't need to have it at all.
You could change get_names to use a reference argument instead of a pointer argument. This is a better practice.
int get_names(string& Family_input)
{
int i=0;
string input="";
while (input!="0")
{
cout << "type " << i <<" member\n";
cin >> input;
Family_input += input; // Just keep on appending to the input argument.
Family_input += "\n"; // Add a newline to separate the inputs.
i++;
}
return i;
}
Then, change the call to get_names. Instead of using
family_number=get_names(familia);
use
family_number=get_names(familia_string);
You get seg fault because you haven't allocate memory for an array of strings.
*(Family_input + old_input.length()) = input;
This is total nonsense. If you'd have an array you increment index only by one not by length of string.
If you want to save different names in different string objects I would suggest:
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
void print_string(string** Value, int const nSize);
void get_names(string** Family_input, int count);
int main(int nNumberofArgs, char* pszArgs[]) {
cout << "This program stores your family members\n";
int family_number;
cout << "Types the number of family members";
cin >> family_number;
/*allocate the number of string pointers that you need*/
string** familia = new string*[family_number];
cout << "Type the names\n";
get_names(familia, family_number);
cout << "The family members are: ";
print_string(familia, family_number);
cout << endl;
return 0;
}
void get_names(string** Family_input, int count) {
for(int i = 0 ; i < count; i++){
cout << "type " << i << " member\n";
/*create a string obj in the heap memory*/
string *input = new string ("");
// using that way you get only a single word
cin >> *input;
/*create a string object on the stack and put its pointer in the family_array*/
Family_input[i] = input;
}
}
void print_string(string** Value, int const nSize) {
for (int i = 0; i < nSize; i++) {
cout << *(Value[i]) << " ";
}
}
First off, thanks in advance for your help. This issue is driving me nuts.
I have a program that accepts a c-string, and then can count the number of vowels and consonants. This works without issue. However, I also need to include a function that allows the user to create a new string. The problem is, though, when the user selects "new string" from the menu, it just loops through the newString() method, without waiting for the user's input. It then creates a new, blank screen.
Here is the entire program. The newString() method is at the end.
#include <iostream>
using namespace std;
// function prototype
void printmenu(void);
int vowelCount(char *);
int consCount(char *);
int cons_and_vowelCount(char *);
void newString(char *, const int);
int main() {
const int LENGTH = 101;
char input_string[LENGTH]; //user defined string
char choice; //user menu choice
bool not_done = true; //loop control flag
// create the input_string object
cout << "Enter a string of no more than " << LENGTH-1 << " characters:\n";
cin.getline(input_string, LENGTH);
do {
printmenu();
cin >> choice;
switch(choice)
{
case 'a':
case 'A':
vowelCount(input_string);
break;
case 'b':
case 'B':
consCount(input_string);
break;
case 'c':
case 'C':
cons_and_vowelCount(input_string);
break;
case 'd':
case 'D':
newString(input_string, LENGTH);
break;
case 'e':
case 'E':
exit(0);
default:
cout << endl << "Error: '" << choice << "' is an invalid selection" << endl;
break;
} //close switch
} //close do
while (not_done);
return 0;
} // close main
/* Function printmenu()
* Input:
* none
* Process:
* Prints the menu of query choices
* Output:
* Prints the menu of query choices
*/
void printmenu(void)
{
cout << endl << endl;
cout << "A) Count the number of vowels in the string" << endl;
cout << "B) Count the number of consonants in the string" << endl;
cout << "C) Count both the vowels and consonants in the string" << endl;
cout << "D) Enter another string" << endl;
cout << "E) Exit the program" << endl;
cout << endl << "Enter your selection: ";
return;
}
int vowelCount(char *str) {
char vowels[11] = "aeiouAEIOU";
int vowel_count = 0;
for (int i = 0; i < strlen(str); i++) {
for (int j = 0; j < strlen(vowels); j++) {
if (str[i] == vowels[j]) {
vowel_count++;
}
}
}
cout << "String contains " << vowel_count << " vowels" << endl;
return vowel_count;
} // close vowelCount
int consCount(char *str) {
char cons[43] = "bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ";
int cons_count = 0;
for (int i = 0; i < strlen(str); i ++) {
for (int j = 0; j < strlen(cons); j++) {
if (str[i] == cons[j]) {
cons_count++;
}
}
}
cout << "String contains " << cons_count << " consonants" << endl;
return cons_count;
} // close consCount
int cons_and_vowelCount(char *str) {
int cons = consCount(str);
int vowels = vowelCount(str);
int total = cons + vowels;
cout << "The string contains a total of " << total << " vowels and "
"consonants" << endl;
return total;
}
void newString(char *str, int len) {
cout << "Enter a string of no more than " << len-1 << " characters:\n";
cin.getline(str, len);
return;
}
The statement cin >> choice only consumes the character they type, not the carriage return that follows. Thus, the subsequent getline() call reads an empty line. One simple solution is to call getline() instead of cin >> choice and then use the first character as the choice.
BTW, the while (not done) should immediately follow the do { … }, and the return 0 is redundant. Also, you should call newString at the start of the program instead of repeating its contents.
cin >> choice leaves a newline in the input stream.. which cause the next getline() to consume it and return. There are many ways.. one way is to use cin.ignore() right after cin >> choice.
The cin >> choice only consumes one character from the stream (as already mentioned). You should add
cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
right after cin>>choice to ignore all the characters that come into the stream after reading the choice.
p.s. #include <limits>