setting char arrays equal to eachother with isdigit and isalpha - c++

Im trying to set a char array equal to 2 other arrays depending on if the element in the first array is a number or a letter. The code makes logical sense to me but the output for the 2 other strings after the for loop doesn't correspond to the logic. Is it because of a missing null value somewhere in the other 2 loops or is the code itself invalid? arrayAlpha, arrayNum, and palind are all char arrays set to a length of 30 elements while string length was already determined before the for loop began.
for(int k=0; k<=stringLength; k++)
{
if( isalpha(palind[k])){
arrayAlpha[k]=palind[k];}
if ( isdigit(palind[k]))
{
arrayNum[k]=palind[k];
}
}

Given the input:
char palind[30] = "12345abcde";
arrayAlpha is garbage.
arrayNum is "12345"
However,
char palind[30] = "abcde12345";
arrayAlpha is "abcde".
arrayNum is garbage.
Thus, [k] is the problem when used in your arrayNum or arrayAlpha which doesn't start with 0.
Simple change will just be subtracting the length of the other.
arrayAlpha[k - strlen(arrayNum)] = palind[k];
arrayNum[k - strlen(arrayAlpha)] = palind[k];
since lengthOfPalind = lengthOfArrayAlpha + lengthOfArrayNum assuming palind only contains letters or numbers.

Related

How to sort non-numeric strings by converting them to integers? Is there a way to convert strings to unique integers while being ordered?

I am trying to convert strings to integers and sort them based on the integer value. These values should be unique to the string, no other string should be able to produce the same value. And if a string1 is bigger than string2, its integer value should be greater. Ex: since "orange" > "apple", "orange" should have a greater integer value. How can I do this?
I know there are an infinite number of possibilities between just 'a' and 'b' but I am not trying to fit every single possibility into a number. I am just trying to possibly sort, let say 1 million values, not an infinite amount.
I was able to get the values to be unique using the following:
long int order = 0;
for (auto letter : word)
order = order * 26 + letter - 'a' + 1;
return order;
but this obviously does not work since the value for "apple" will be greater than the value for "z".
This is not a homework assignment or a puzzle, this is something I thought of myself. Your help is appreciated, thank you!
You are almost there ... just a minor tweaks are needed:
you are multiplying by 26
however you have letters (a..z) and empty space so you should multiply by 27 instead !!!
Add zeropading
in order to make starting letter the most significant digit you should zeropad/align the strings to common length... if you are using 32bit integers then max size of string is:
floor(log27(2^32)) = 6
floor(32/log2(27)) = 6
Here small example:
int lexhash(char *s)
{
int i,h;
for (h=0,i=0;i<6;i++) // process string
{
if (s[i]==0) break;
h*=27;
h+=s[i]-'a'+1;
}
for (;i<6;i++) h*=27; // zeropad missing letters
return h;
}
returning these:
14348907 a
28697814 b
43046721 c
373071582 z
15470838 abc
358171551 xyz
23175774 apple
224829626 orange
ordered by hash:
14348907 a
15470838 abc
23175774 apple
28697814 b
43046721 c
224829626 orange
358171551 xyz
373071582 z
This will handle all lowercase a..z strings up to 6 characters length which is:
26^6 + 26^5 +26^4 + 26^3 + 26^2 + 26^1 = 321272406 possibilities
For more just use bigger bitwidth for the hash. Do not forget to use unsigned type if you use the highest bit of it too (not the case for 32bit)
You can use position of char:
std::string s("apple");
int result = 0;
for (size_t i = 0; i < s.size(); ++i)
result += (s[i] - 'a') * static_cast<int>(i + 1);
return result;
By the way, you are trying to get something very similar to hash function.

Error with big number of characters while making a letter pyramid

The task is to make a letter pyramid. I have done it but its behaviour goes very strange after I pass a certain number of characters that were inputed. Looking forward to an answer.
string input{};
string reverseString{};
getline(cin,input);
for(int j = input.length()-1;j>=0;j--){
reverseString += input.at(j);
}
for(int i = 0;i<input.length();i++){
int numberOfSpaces {};
numberOfSpaces = input.length()-i;
string spaces(" ",numberOfSpaces);
cout<< spaces << input.substr(0,i) << input.at(i)<<reverseString.substr(numberOfSpaces,i) <<spaces<<endl;
}
This is an example of the input/output:
string spaces(" ",numberOfSpaces);
This doesn't do what you think it does.
This constructor takes an array and a count.
It copies count (in this case numberOfSpaces) items from the passed in array.
The passed in array has length 1 (technically 2 with the null terminator), and so anything > 2 will cause undefined behaviour as it reads off the end of the array.

String array length C++ issue?

I've understood that string arrays end with a '\0' symbol. So, the following code should print 0, 1, 2 and 3. (Notice I'm using a range-based for() loop).
$ cat app.cpp
#include <iostream>
int main(){
char s[]="0123\0abc";
for(char c: s) std::cerr<<"-->"<<c<<std::endl;
return 0;
}
But it does print the whole array, including '\0's.
$ ./app
-->0
-->1
-->2
-->3
-->
-->a
-->b
-->c
-->
$ _
What is happening here? Why is the string not considered to end with '\0'? Do C++ collections consider (I imagine C++11) strings differently than in classical C++?
Moreover, the number of characters in "0123\0abc" is 8. Notice the printout makes 9 lines!
(I know that std::cout<< runs fine, as well as strlen(), as well as for(int i=s; s[i]; i++), etc., I know about the end terminator, that's not the question!).
s is of type char [9], i.e. an array containing 9 chars (including the null terminator char '\0'). Ranged-based for loop just iterators over all the 9 elements, the null terminator char '\0' is not considered specially.
Executes a for loop over a range.
Used as a more readable equivalent to the traditional for loop
operating over a range of values, such as all elements in a container.
for(char c: s) std::cerr<<"-->"<<c<<std::endl; produces code prototype equivalent to
{
auto && __range = s ;
auto __begin = __range ; // get the pointer to the beginning of the array
auto __end = __range + __bound ; // get the pointer to the end of the array ( __bound is the number of elements in the array, i.e. 9 )
for ( ; __begin != __end; ++__begin) {
char c = *__begin;
std::cerr<<"-->"<<c<<std::endl;
}
}
When you declare a char[] as char s[] = "0123\0abc" (a string literal), s becomes a char[9]. The \0 is included because it needs space too.
The range-based for-loop you use does not consider the char[9] as anything else than an array containing char with the extent 9 and will happily provide every element in the array to the inner workings of your loop. The \0 is just one of the chars in this context.
Be aware that char not necessarily needs to define a character only – it can be used to store any arbitrary 8-bit value (on some machines, char is wider, though, encountered one with a 16-bit char already – then there's no int8_t available...), although signed char or unsigned char – according to specific needs – should be preferred, as signedness of char is implementation defined (or even better: int8_t or uint8_t from cstdint header, provided they are available).
So your string literal actually is just an array of nine integral values (just as if you had created an int-array, only the type usually is narrower). A range based for loop will iterate over all of these nine 8-bit integers, and you get the output in your example.
These integral values only get a special meaning in specific contexts (functions), such as printf, puts or even operator>>, where they are then interpreted as characters. When used as C-strings, a 0 value inside such an array marks the end of the string – but this 0-character still is part of that string. For illustration: puts might look like this:
int puts(char const* str)
{
while(!*str) // stops on encountering null character
{
char c = *str;
// + get pixel representation of c for console, e. g 'B' for 66
// + print this pixel representation to current console position
// + advance by one position on console
++str;
}
return 0; // non-negative for success, could return number of
// characters output as well...
}
Here s is an array of char, so it includes \0 too.
When you use for(char c: s), the loop will search all char in the array.
But in C, the definition tells us:
A string is a contiguous sequence of characters terminated by and including the first null character.
And
[...] The length of a string is the number of bytes preceding the null character and the value of a string is the sequence of the values of the contained characters...
So, when you use C standard functions to print the array s as a string, you will see the result that you wanted. Example: printf("%s", s);
"the number of characters in "0123\0abc" is 8. Notice the printout makes 9 lines!"
Again, printf("%s; Len = %d", s, strlen(s)); runs fine!

How exactly does a reference to an array work?

I am looking at a unique example here and am trying to understand why his snippet behaves the way it does
// uninitialized mem
char test[99999];
//
test[0] = 'a';
test[1] = 'b';
test[2] = 'c';
test[3] = 'd';
test[4] = 'e';
test[5] = 'f';
test[6] = 'g';
for (int i = 0; i < 99999; i++) {
cout << (&test[i])[i] << endl;
}
In particular, what is happening in memory for the output to skip a character?
output:
a
c
e
g
..
This is what is happening:
An array is just a contiguous chunk of memory.
&test
Is getting the address of that index of the starting point of array. Not the value.
When you add [some number], it counts up the number times the size of the data type, in this case each char is a byte.
So when you do
&test[i]
that means the starting address + i bytes.
when you do
(&test[i])[i]
You are doing i bytes from the starting address, and then treat that as the starting address and go up i more bytes.
So in your iterations:
(&test[0])[0] // index 0 + 0 = 0
(&test[1])[1] // index 1 + 1 = 2
(&test[2])[2] // index 2 + 2 = 4
(&test[3])[3] // index 3 + 3 = 6
It should become a bit more obvious when you consider what the array indexing is actually doing.
Given an array test, you usually access the nth element of test with test[n]. However, this is actually the equivalent of *(test+n). This is because addition on pointers automatically multiplies the amount you add with the size of the type being pointed to. This means the pointer will then be pointing at the second item in the array if you add one to the pointer, the third item if you add two, and so on.
The code you provide then references that value, so you end up with &(*(test+n)). The reference (&) and the dereference (*) operations then cancel each other out, which means you end up with just test+n.
The code then does another array index on that value, so you end up with (test+n)[n], which again may be written as *((test+n)+n). If you simplify that, you get *(test+n+n), which may be rewritten as *(test+2*n).
Clearly then, if you convert that back to array indexing notation, you end up with test[2*n], which indicates in simple form that you'll be querying every other element of the array.

converting integer into char explictly

I am trying to convert integer into character. I know how to convert character to integer like this int(a) where a is a character. But when I am trying to convert integer to character, it is giving me a symbolic value. Please help me out.
I am doing something like below. Thanks in advance.
int a=0;
char str1[20];
for(int i=0;i<size;i++)
//somecalculation that sets value in a everytime and stores in str1
str1[i]=char(a)-'A'
Well I am running for loop and setting values in str1. This is just little of my code.
You could use str1[i] = static_cast<char>(a + '0');. This will convert a = 0 to '0', a = 1 to '1' etc. Consider the behaviour as undefined outside the range 0, ..., 9.
just use sprintf:
for(int i=0;i<size;i++)
//somecalculation that sets value in a everytime and stores in str1
sprintf(str1 + i, "%i", a);
since you noted that a is each time only a one digit integer, this should work, but this is not very error prone... normally you should check on how much digits were written:
for(int i=0;i<size;i++)
//somecalculation that sets value in a everytime and stores in str1
if (sprintf(str1 + i, "%i", a) != 1)
printf("expected to print only one character!\n");