Writing value to c style string in struct - c++

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.

Related

How to declare function using reference?

I am making this program to check the alphabetic and numeric characters of a C-type string. I am using C-type strings because it is for an assignment, otherwise I would opt to use std::string.
How do I declare the function? In my case, I want str, SAlpha and SNum, to be stored in the function as s, alpha, num. That's why I am using references, but I don't understand how to declare it without giving me an error saying undefined.
I have been searching, but I am new to functions, and don't understand them quite well. That's why I'm asking.
Below is the code:
#include <iostream>
#include <cstring>
#include <cctype>
using namespace std;
void seperate(char (&s)[], char (&alpha)[], char (&num)[]);
int main() {
char str[100];
char SAlpha[100];
char SNum[100];
cout << "Insert a string: ";
cin.getline(str,100);
strcpy(SAlpha, str);
strcpy(SNum,str);
cout << "Alphabetic characters " << endl;
for (int i = 0; i < strlen(SAlpha); i++) {
if (isalpha(SAlpha[i])) {
cout << " " << SAlpha[i];
}
}
cout << endl;
cout << "Numeric characters " << endl;
for (int i = 0; i < strlen(SNum);i++) {
if (isdigit(SNum[i])) {
cout << " " << SNum[i];
}
}
seperate(str, SAlpha, SNum); //UNDEFINED FUNCTION
return 0;
}
You are getting an "undefined" error because you have only declared the seperate() function but have not implemented it yet, eg:
#include <iostream>
#include <cstring>
#include <cctype>
using namespace std;
// THIS IS JUST A DECLARATION!!!
void seperate(char (&s)[100], char (&alpha)[100], char (&num)[100]);
int main() {
char str[100];
char SAlpha[100];
char SNum[100];
cout << "Insert a string: ";
cin.getline(str,100);
strcpy(SAlpha, str);
strcpy(SNum,str);
cout << "Alphabetic characters " << endl;
for (int i = 0; i < strlen(SAlpha); i++) {
if (isalpha(SAlpha[i])) {
cout << " " << SAlpha[i];
}
}
cout << endl;
cout << "Numeric characters " << endl;
for (int i = 0; i < strlen(SNum);i++) {
if (isdigit(SNum[i])) {
cout << " " << SNum[i];
}
}
seperate(str, SAlpha, SNum); // <-- OK TO CALL SINCE THE FUNCTION IS DECLARED ABOVE...
return 0;
}
// ADD THIS DEFINITION!!!
void seperate(char (&s)[100], char (&alpha)[100], char (&num)[100])
{
// do something here...
}

Binary char array into stringstream and pop from the buffer

I have 20byte binary char array. I want to divide into 3 parts: 4byte, 8byte, 8byte. I implemented it like the following. It works but seems I might be able to use buffer stream. I want to know how to use it.
Now
void main()
{
// _data is 20byte binary char array. 0000000000000000000000000000000000000000000001111001110001111111001110000010110000001011101101000000000000000000000000000000000000000000000000000000000000000001
// strA (4 byte)
string strA;
for (std::size_t i = 0; i < 4; ++i) {
strA += bitset<8>(_data.c_str()[i]).to_string();
}
cout << strA << endl; // 00000000000000000000000000000000
// strB (8 byte)
string strB;
for (std::size_t i = 4; i < 12; ++i) {
strB += bitset<8>(_data.c_str()[i]).to_string();
}
cout << strB << endl; // 0000000000000111100111000111111100111000001011000000101110110100
// strC (8 byte)
string strC;
for (std::size_t i = 12; i < 20; ++i) {
strC += bitset<8>(_data.c_str()[i]).to_string();
}
cout << strC << endl; // 0000000000000000000000000000000000000000000000000000000000000001
}
Expectation
I want to implement like this.
void main()
{
stringstream ss = _data;
strA = ss.pop(4);
strB = ss.pop(8);
strC = ss.pop(8);
}
Update 1
Thank you guys. I'm trying all of answers you gave me one by one. I'm newbie in c++ so it takes time to understand it. The following is Anders K's one.
struct S { char four[4]; char eight1[8]; char eight2[8]; };
struct S *p = reinterpret_cast<S*>(&_data);
cout << p->four << endl; // => Output "(" I think I can find way to output
Update 2
It works using string::substr. Thanks Zakir.
int main()
{
// I don't know how to change to string value in smart way..
string str;
for (std::size_t i = 0; i < _data.size(); ++i) {
str += bitset<8>(_data.c_str()[i]).to_string();
}
cout << str << endl; // 0000000000000000000000000000000000000000000001111001110001111111001110000010110000001011101101000000000000000000000000000000000000000000000000000000000000000001
std::string d = str; // Your binary stream goes here
int lenA = (4*8); // First 4 Bytes
int lenB = (8*8); // Second 8 Bytes
int lenC = (8*8); // Last 8 Bytes
std::string strA = d.substr(0, lenA);
std::string strB = d.substr(lenA + 1, lenB - 1);
std::string strC = d.substr(lenA + lenB + 1, lenC - 1);
cout << strA << endl; // 00000000000000000000000000000000
cout << strB << endl; // 000000000000111100111000111111100111000001011000000101110110100
cout << strC << endl; // 000000000000000000000000000000000000000000000000000000000000001
}
Update 3
I got an error when I try Scheff's way. This is my fault and I think I can solve it. And I think I should reconsider about _data's type.
int main
{
const char data = _data;
const char *iter = data;
string strA = pop(iter, 4);
string strB = pop(iter, 8);
string strC = pop(iter, 8);
cout << "strA: '" << strA << "'" << endl;
cout << "strB: '" << strB << "'" << endl;
cout << "strC: '" << strC << "'" << endl;
}
Make Error Message
error: no viable conversion from 'string' (aka 'basic_string<char, char_traits<char>, allocator<char> >') to
'const char'
const char data = _data;
It is not possible to make a new method for std::stringstream. (At least, I would not recommend this.)
Instead, I would suggest to make it a function. The usage would be similar.
#include <bitset>
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
string pop(istream &in, size_t n)
{
string ret;
while (n--) {
unsigned char byte = (unsigned char)in.get();
ret += bitset<8>(byte).to_string();
}
return ret;
}
int main()
{
string data(
"\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa"
"\xbb\xcc\xdd\xee\xff\xde\xad\xbe\xef\x00", 20);
istringstream in; in.str(data);
string strA = pop(in, 4);
string strB = pop(in, 8);
string strC = pop(in, 8);
cout << "strA: '" << strA << "'" << endl;
cout << "strB: '" << strB << "'" << endl;
cout << "strC: '" << strC << "'" << endl;
return 0;
}
Output:
strA: '00010001001000100011001101000100'
strB: '0101010101100110011101111000100010011001101010101011101111001100'
strC: '1101110111101110111111111101111010101101101111101110111100000000'
Note:
Using a std::istream makes it applicable to any stream derived from std::istream.
There is no error handling in pop(). Thus, the returned result of pop() might be wrong if the passed stream isn't good() afterwards.
Btw. I agree with the comments that a std::stream might be "over-engineered". Thus, here the "light-weight" version:
#include <bitset>
#include <iostream>
#include <string>
using namespace std;
string pop(const char *&iter, size_t n)
{
string ret;
while (n--) {
ret += bitset<8>((unsigned char)*iter++).to_string();
}
return ret;
}
int main()
{
const char data[] =
"\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa"
"\xbb\xcc\xdd\xee\xff\xde\xad\xbe\xef\x00";
const char *iter = data;
string strA = pop(iter, 4);
string strB = pop(iter, 8);
string strC = pop(iter, 8);
cout << "strA: '" << strA << "'" << endl;
cout << "strB: '" << strB << "'" << endl;
cout << "strC: '" << strC << "'" << endl;
return 0;
}
The output is identical like above.
Note:
The usage of char[] and char* is much more sensitive for out-of-bound access. Thus, it has to be used carefully.
I'm not quite sure whether the (unsigned char) cast is necessary. As I have often seen "funny" effects concerning char, int and sign extension, I guess it cannot hurt. (I feel better with it.)
I can propose you a very simple alternative using string::substr
#include <iostream>
#include <string>
using namespace std;
int main ()
{
string _data="00010001001000100011001101000100\
0101010101100110011101111000100010011001101010101011101111001100\
1101110111101110111111111101111010101101101111101110111100000000";
int lenA = (4*8); //First 4 Bytes
int lenB = (8*8); //Second 8 Bytes
int lenC = (16*8); //Last 16 Bytes
string strA = _data.substr(0, lenA - 1);
string strB = _data.substr(lenA, lenB - 1);
string strC = _data.substr(lenB, lenC - 1);
std::cout << "strA: " << strA << endl;
std::cout << "strB: " << strB << endl;
std::cout << "strC: " << strC << endl;
return 0;
}
This is neat and simple but gets your job done!
Demo here
Output:-
strA: 0001000100100010001100110100010
strB: 010101010110011001110111100010001001100110101010101110111100110
strC: 100110011010101010111011110011001101110111101110111111111101111010101101101111101110111100000000

C++ Trouble Modifying A String

So in this program I'm trying to go through word by word and make it only lowercase letters, no whitespace or anything else. However, my string "temp" isn't holding anything in it. Is it because of the way I'm trying to modify it? Maybe I should try using a char * instead? Sorry if this is a stupid question, I'm brand new to c++, but I've been trying to debug it for hours and can't find much searching for this.
#include <string>
#include <iostream>
#include <fstream>
#include <ctype.h>
using namespace std;
int main(int argc, char* argv[]) {
/*if (argc != 3) {
cout << "Error: wrong number of arguments." << endl;
}*/
ifstream infile(argv[1]);
//infile.open(argv[1]);
string content((std::istreambuf_iterator<char>(infile)),
(std::istreambuf_iterator<char>()));
string final;
string temp;
string distinct[5000];
int distinctnum[5000] = { 0 };
int numdist = 0;
int wordcount = 0;
int i = 0;
int j = 0;
int k = 0;
int isdistinct = 0;
int len = content.length();
//cout << "test 1" << endl;
cout << "length of string: " << len << endl;
cout << "content entered: " << content << endl;
while (i < len) {
temp.clear();
//cout << "test 2" << endl;
if (isalpha(content[i])) {
//cout << "test 3" << endl;
if (isupper(content[i])) {
//cout << "test 4" << endl;
temp[j] = tolower(content[i]);
++j;
}
else {
//cout << "test 5" << endl;
temp[j] = content[i];
++j;
}
}
else {
cout << temp << endl;
//cout << "test 6" << endl;
++wordcount;
final = final + temp;
j = 0;
for (k = 0;k < numdist;k++) {
//cout << "test 7" << endl;
if (distinct[k] == temp) {
++distinctnum[k];
isdistinct = 1;
break;
}
}
if (isdistinct == 0) {
//cout << "test 8" << endl;
distinct[numdist] = temp;
++numdist;
}
}
//cout << temp << endl;
++i;
}
cout << wordcount+1 << " words total." << endl << numdist << " distinct words." << endl;
cout << "New output: " << final << endl;
return 0;
}
You can't add to a string with operator[]. You can only modify what's already there. Since temp is created empty and routinely cleared, using [] is undefined. The string length is zero, so any indexing is out of bounds. There may be nothing there at all. Even if the program manages to survive this abuse, the string length is likely to still be zero, and operations on the string will result in nothing happening.
In keeping with what OP currently has, I see two easy options:
Treat the string the same way you would a std::vector and push_back
temp.push_back(tolower(content[i]));
or
Build up a std::stringstream
stream << tolower(content[i])
and convert the result into a string when finished
string temp = stream.str();
Either approach eliminates the need for a j counter as strings know how long they are.
However, OP can pull and endrun around this whole problem and use std::transform
std::transform(content.begin(), content.end(), content.begin(), ::tolower);
to convert the whole string in one shot and then concentrate on splitting the lower case string with substring. The colons in front of ::tolower are there to prevent confusion with other tolowers since proper namespacing of the standard library has been switched off with using namespace std;
Off topic, it looks like OP is performing a frequency count on words. Look into std::map<string, int> distinct;. You can reduce the gathering and comparison testing to
distinct[temp]++;

Trying to make string array passed through methods C++

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.

How do you convert an int into a string in c++

I want to convert an int to a string so can cout it. This code is not working as expected:
for (int i = 1; i<1000000, i++;)
{
cout << "testing: " + i;
}
You should do this in the following way -
for (int i = 1; i<1000000, i++;)
{
cout << "testing: "<<i<<endl;
}
The << operator will take care of printing the values appropriately.
If you still want to know how to convert an integer to string, then the following is the way to do it using the stringstream -
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
int number = 123;
stringstream ss;
ss << number;
cout << ss.str() << endl;
return 0;
}
Use std::stringstream as:
for (int i = 1; i<1000000, i++;)
{
std::stringstream ss("testing: ");
ss << i;
std::string s = ss.str();
//do whatever you want to do with s
std::cout << s << std::endl; //prints it to output stream
}
But if you just want to print it to output stream, then you don't even need that. You can simply do this:
for (int i = 1; i<1000000, i++;)
{
std::cout << "testing : " << i;
}
Do this instead:
for (int i = 1; i<1000000, i++;)
{
std::cout << "testing: " << i << std::endl;
}
The implementation of << operator will do the necessary conversion before printing it out. Use "endl", so each statement will print a separate line.