I'm trying to add the digits times their index in order to create a hash, but this doesn't seem to give the correct output. Can anyone tell me what's wrong here?
int main(){
int i, hash=0, input;
char temp[30];
cin>>input;
itoa (input, temp, 10);
for(i=0; i<(sizeof(temp)/sizeof(*temp)); i++){
hash+=((temp[i])*i);
}
cout<<hash;
return 0;
}
It's because itoa() returns a C-String.
Every C-String is a buffer (just like temp[30]), but not every buffer is a C-String.
The C-String must contain characters from a list of valid things (alphanumerical + some symbols + etc) and MUST finish with the "string terminator" (the character '\0')
Your temp variable is not initialized (we could say it was born as a generic buffer, not a string yet), so after itoa() you will have your "number" converted to string (your buffer just became a C-String), but after the string terminator ('\0') you will have any trash, once you did not initialized it!
Your buffer will be like this:
temp[30] = { '1', '2', '3', '\0', ?, ?, ?, ..., ? }
The ?'s could be anything...
Because you loop over the whole buffer temp[30] you will be making a sum of different things all the time.
Solution 1: Initialize char temp[30] = { 0 } (a little stupid, but valid)
Solution 2: Loop up to the "length" of the C-String temp, instead of the whole buffer (this
one makes more sense!)
This this:
size_t length( strlen( temp ) );
for ( size_t i( 0 ); i < length; i++ )
{
hash += (int)i * temp[ i ];
}
Yes, you are hashing all the 30 bytes of temp[30] instead of hashing only the ascii representation of the integer number you are reading from stdin.
I think this is closer to what you want:
#include <iostream>
using namespace std;
int main() {
int hash = 0;
// Read input from stdin
std::string input;
std::cin >> input;
// Make sure it contains only numbers
if (input.find_first_not_of("0123456789") != std::string::npos) {
std::cout << "Input doesn't contain only digits" << std::endl;
return 1;
}
for (int i = 0; i < input.size(); i++) {
hash += (input[i] - '0') * i;
}
std::cout << hash << std::endl;
return 0;
}
That temp[] buffer is not completely filled by itoa(), so you will be hashing garbage if you loop over i=0 to (sizeof temp)-1. Try:
for (size_t i=0, n=strlen(temp); i<n; ++i)
{
hash += (int)i*temp[i];
}
You'll need <cstring> included to define strlen().
On second thought, the no-<cstring> approach is probably better:
for (int i=0; temp[i] != 0; ++i)
{
hash += i*temp[i];
}
That eliminates the (int) cast too.
Related
I am trying to store a sentence to a 2d array by separating each words. In the 2d array each row will contain each word from the sentence. Here is what I think I should do.
//Logic
//given string mystring
string mystring = "testing the arrays";
//create a 2d char array to hold 4 words with 10 max size
char 2darr[4][10] = {" "};
int x = 0;
for (int i = 0,j=0; i <mystring.length(); i++)
{
if (mystring(i) != ' ')
2darr[x][j++] = mystring(i); //copy the each character to the first row
else
2darr[x][j++] = '\0';
++x; // goes to next row
j = 0; //reset j for new row
}
Is there a better way to do this? I think my logic is a little off as well
The better way to do this is:
1) There is no need to check spaces. For this to occur, you can use std::istringstream with operator >> to obtain each word in a loop.
2) Use strncpy to copy the string into the 2 dimensional array
3) You need to make sure that the string does not exceed the bounds of the array, and that you have no more than 4 separate words.
Here is an example:
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <cstring>
int main()
{
char arr2d[4][10] = {};
std::string mystring = "testing the arrays";
// create an input stream containing the test string
std::istringstream strm(mystring);
std::string word;
// this is the word count
int curCount = 0;
// obtain each word and copy to the array
while (strm >> word && curCount < 4)
strncpy(arr2d[curCount++], word.c_str(), 9);
// output the results
for (int i = 0; i < curCount; ++i)
std::cout << arr2d[i] << "\n";
}
Output:
testing
the
arrays
this expression char 2darr[4][10] = {" "} will only set the first element to be " ", the others will be '\0' or NULL. But it is probably OK, since it is the default terminator of C-strings.
Variables can't start with a digit, call it arr2d instead.
String character access is mystring[i], not mystring(i)
You only indented the lines in the else block, in C++ if you don't enclose a block with curly braces, it only captures the first row, what you basically wrote is:
else {
2darr[x][j++] = '\0';
}
++x; // goes to next row
j = 0; //reset j for new row
Corrected code is
std::string mystring = "testing the arrays";
//create a 2d char array to hold 4 words with 10 max size
char arr2d[4][10] = { };
int x = 0;
for (int i = 0, j = 0; i < mystring.length(); i++)
{
if (mystring[i] != ' ') {
arr2d[x][j++] = mystring[i]; //copy the each character to the first row
}
else {
arr2d[x][j++] = '\0';
++x; // goes to next row
j = 0; //reset j for new row
}
}
I am writing a C++ function that is supposed to duplicate an array of chars by copying each element character-by-character into a new array. Ideally, if I make the statements
char* a = "test";
char* b = copyString(a);
then both a and b should contain the string "test." However, when I print the copied array b, I get "test" plus a series of nonsense characters that seem to be the pointer. I don't want those, but I can't figure out where I'm going wrong.
My current function is as follows:
char* copyString(char* s)
{
//Find the length of the array.
int n = stringLength(s);
//The stringLength function simply calculates the length of
//the char* array parameter.
//For each character that is not '\0', copy it into a new array.
char* duplicate = new char[n];
for (int j = 0; j < n; j++)
{
duplicate[j] = s[j];
//Optional print statement for debugging.
cout << duplicate[j] << endl;
}
//Return the new array.
return duplicate;
}
For the purposes of understanding certain aspects of C++, I cannot use string libraries, which is where other answers I have found have fallen short in this case. Any help with this problem is greatly appreciated.
EDIT: I though my stringLength function was fine - perhaps I was wrong.
int stringLength(char* s)
{
int n;
//Loop through each character in the array until the '\0' symbol is found. Calculate the length of the array.
for (int i = 0; s[i] != '\0'; i++)
{
n = i + 1;
}
//Optional print statement for debugging.
// cout << "The length of string " << s << " is " << n << " characters." << endl;
return n;
}
You need to copy the 0 too. That's what a C-style string is, a null-terminated character array.
Really, all you need to do is add one to the length:
int n = stringLength(s) + 1; // include the '\0'
And then everything else will account for itself - you'll allocate an array of sufficient size, and copy the '\0' in your loop too.
so I'm working on a project that I have to read contents from a file and then analyze them. But I'm having a problem with getting the string out of a pointer that contains the address to what I need.
string lePapel(vector<char> vec){
string *str, s;
int i, j = 0;
vector<char> aux;
aux.resize(6);
for (i = 57; i <= 62; i++){
aux[j] = vec[i];
j++;
}
str = new string[aux.size()];
for (i = 0; i < 6; i++){ str[i] = aux[i]; }
return s;
}
So, the file contains in the array positions from 57 to 62 the word: ABCB4, but when returning the string s my output is A only as expected because of the pointer.
The thing is that I have been trying to find a solution and storing the whole content from vec[57] to vec[64] into the string s and returning it, and the closest that I got to returning anything plausible was using a pointer.
So, now to my question, how can I iterate the *str pointer and copy the whole content to s and return it?
Thanks in advance
I'd suggest you to not use pointers on string in your case. The following code is probably what you want :
#include <iostream>
#include <string>
#include <vector>
using namespace std;
string lePapel(vector<char> vec){
int j = 0;
vector<char> aux;
aux.resize(6);
for (int i = 57; i <= 62; i++){
aux[j] = vec[j];
j++;
}
string str;
str.reserve(6);
for (int i = 0; i < 6; i++){ str.push_back(aux[i]); }
return str;
}
int main() {
char x[5] = {'A', 'B', 'C', 'B', '4'};
vector<char> vec(x, x + 5);
string s = lePapel(vec);
cout << s;
return 0;
}
Tested here : Tested code
About reserving space to your vector : c++ vector::reserve
Same for strings : reserve for strings
The dynamic array of string objects and the whole aux vector seem completely needless here (unless there's some other purpose for them in your code). Additionally, str is currently causing a memory leak because you never delete it when you're finished.
A much simpler approach is just to append the characters one-at-a-time to the s string object (assuming it's a std::string):
string lePapel(vector<char> vec) {
string s;
for (int i = 57; i <= 62; i++) {
s += vec[i];
}
return s;
}
There are various ways to make the code even shorter (and more efficient) than that though, if you really want to.
EDIT: If you still need/want to iterate your dynamic array and concatenate the contents into s, here's how you could do it:
for (i = 0; i < 6; i++) s += str[i];
delete [] str; //<-- very important!
Short answer, you don't want a string * you want a char *. What you created is a string array. String objects contain a pointer to the char * data you are trying to capture. Also, the sizeof(std::string) (8 bytes in size) is a lot bigger than sizeof(char) (1 byte in size) the second character you store is 8 bytes away from the first character instead of being adjacent.
There are a lot of other C++ style and safety concerns, but I'll stick with the question. ;)
For some weird reason, it keeps on creating uninitilized values when I pass in the length as 12, it creates an array of about 16 and stores the rest with crap that I don't want. Anyone know why this isn't working? It's for an assignment that's due tomorrow and this is my last problem... Any help would be appreciated thanks.
char * convertToUppercase (char* toUpSize, int length) {
std::cout << "ToUpsize: " << toUpSize << "\nLength: " << length << "\n";
char * upsized = new char[length];
for (int i = 0; toUpSize[i]; i++) {
upsized[i] = toupper(toUpSize[i]);
}
return upsized;
}
I think you either write i< length in the for loop, instead of toUpSize[i] as:
for (int i = 0; i < length; i++) {
upsized[i] = toupper(toUpSize[i]);
}
Or pass toUpSize as null-terminated string if you want to write toUpSize[i] in the for loop condition. If you do so, then you've to put \0 at the end of upsized after you exit from the loop, at index i for which toUpSize[i] is \0. And to accomplish this, you've te move the definition of i outside the for loop, so that you can use it after you exit from the loop.
Null-terminated string is what which has \0 character at the end of the string.
char x[] = {'N', 'a', 'w', 'a', 'z' };
char y[] = {'N', 'a', 'w', 'a', 'z', '\0' };
Here, x is not a null-terminated string, but y is a null-teminated string.
If the strings are defined as:
char z[] = "Nawaz";
const char *s = "Nawaz";
Here z and s are null-terminated string, because both of them are created out of "Nawaz" which is a null-terminated string. Note that sizeof("Nawaz") would return 6, not 5, precisely because there is an \0 at the end of the string.
You need to null-terminate the returned array if you want to print it like a string. Make sure that it ends with a null-terminator. Depending on how you calculate the length argument you may need to add extra space for it to the array. You may also want to make sure that the array that you pass in is null-terminated.
You need to add the termination char:
char * convertToUppercase (char* toUpSize, int length) {
std::cout << "ToUpsize: " << toUpSize << "\nLength: " << length << "\n";
char * upsized = new char[length];
int i;
for (i = 0; toUpSize[i]; i++) { // stops when you get toUpSize[i]==0
upsized[i] = toupper(toUpSize[i]);
}
upsized[i] = '\0'; //add termination
return upsized;
}
Your code assumes length to be the length of the allocated array, not the length of the string. strlen(toUpSize) counts the chars that are not '\0' from position 0 in toUpSize.
E.g.: strlen("abc\0def") -> 3
sizeof("abc\0def") -> 8!
Why are you even bothering with char pointers? This is C++, not C.
#include <string>
#include <algorithm>
#include <cstring>
#include <iostream>
std::string to_upper_case(std::string str)
{
std::transform(str.begin(), str.end(), str.begin(), toupper);
return str;
}
int main()
{
std::cout << to_upper_case("hello world\n");
}
If you decide to stick to the C solution, reserve one more char for the NUL terminator and put it there:
char * upsized = new char[length + 1]; // note the +1
upsized[length] = 0;
My code basically is to list ASCII codepoints of a string that is input, my following code is simple, here:
#include <iostream>
#include <string.h>
using namespace std;
int main() {
char str[20];
int result[20];
cin >> str;
for(int i = 0; i != strlen(str); i++) {
result[i] = (int)i;
}
for(int i = 0; i != 20; i++)
cout << result[i] << ", ";
}
when I run it, no matter what the input it outputs a pile of gibberish like undefined memory like so:
0, 1, 2, 3, 4, 5, 1, -1217349408, -1220040795, -1220041307, -1076427112, 134514781, -1218903292, 134519344, -1076427096, 134514004, -1217411568, 134519344, -1076427048, 134514681,
Am I missing something simple in how I append each integer to the array?
Just note this is a simple example, my input will not be larger than 20 characters.
EDIT Typo in my result.. cin>>result was cin>>str
This loop will iterate a number of times equal to the length of 'str'. That is, it will iterate once for each character in 'str', and stop at the 'null terminator' (char value of 0) which is how c strings are ended. In each loop, the value of 'i' is the loop number, starting at 0 - and this is the value you assign to that index in the results array.
for(int i = 0; i != strlen(str); i++) {
result[i] = (int)i;
}
So for example, for a string of length 5, you will assign the values '0, 1, 2 ,3, 4' to the result array at those indexes, respectively. The other values in the result array are not assigned - and so could hold any value (generally, whatever was in that bit of memory before you started using it). If your string is longer than 20 characters, you're in trouble, because you will start trying to access the array at index 20 and beyond, which is not memory that belongs to your program.
This loop prints out all the values in the 'result' array, from the value at index 0 to the value at index 19:
for(int i = 0; i != 20; i++)
cout << result[i] << ", ";
So it will print the initialised values, and, if the string was less than 20 characters long, the uninitialised values as well.
At a minimum, to start getting anything like the results you're after, you want to change
result[i] = (int)i;
to
result[i] = str[i];
but as mentioned by others, and to escape some of the memory access issues I mentioned above, it would be much better if you use an iterator to get the character values.
for(string::iterator i = str.begin(); i != str.end(); i++)
// access char here using '*i'
strlen(str) will give you an undefined output, because you haven't initialised the contents of str[].
Essentially, you failed to correctly initialize the string and you didn't check that it was the correct size. Correct code:
#include <iostream>
#include <string> // NOT <string.h>, <string>
int main() {
std::string str;
std::cin >> str;
std::cin.ignore();
for(std::string::iterator it = str.begin(); it != str.end(); it++) {
std::cout << (int)(*it);
if (it + 1 != str.end())
std::cout << ", ";
else
std::cout << "\n";
}
std::cin.get();
}
You have 3 problems:
You didn't initialise str with a proper string, thus strlen will return an unpredictable value.
You initialise the first strlen(str) positions of result, but later you print it until the index 20. You should use the same condition on both loops.
You should definitely use std::string and its iterator.
You've not initialized str and you are taking its strlen
When you did
cin >> result; // this does not even compile!!!
I guess you meant
cin >> str;
Its not clear what you are trying to do. But you can try this to get some meaningful result:
char str[20];
int result[20] = {0};
cin >> str;
...// rest all unchanged.
stlen( str ) will give the number of characters before the null terminator.
This means that only strlen(str) integers are valid. The rest are uninitialized.
Also: have a look at std::transform. You can avoid the temporary array of integers to achieve the same, or transform right into one.
int to_codepoint( char c ) { return (int) c; }
// ...
char cs[] = "abcd";
std::transform( cs, cs+strlen(cs)
, std::ostream_iterator<int>( std::cout, ", " ), to_codepoint);
// or transform into an array:
int is[ 1000 ]; // 1000 enough?
std::transform( cs, cs+strlen(cs)
, is, to_codepoint );
(test code at codepad.org)