intToStr recursively - c++

This is a task from school, I am supposed to write a recursive function that will convert a given int to a string, I know I'm close but I can't point the missing thing in my code, hints are welcome.
void intToStr(unsigned int num, char s[])
{
if (num < 10)
{
s[0] = '0' + num;
}
else
{
intToStr(num/10, s);
s[strlen(s)] = '0' + num%10;
}
}
Edit: my problem is that the function only works for pre initialized arrays, but if I let the function work on an uninitialized function it will not work.

Unless your array is zero-initialized, you are forgetting to append a null terminator when you modify it.
Just add it right after the last character:
void intToStr(unsigned int num, char s[])
{
if (num < 10)
{
s[0] = '0' + num;
s[1] = 0;
}
else
{
intToStr(num/10, s);
s[strlen(s)+1] = 0; //you have to do this operation here, before you overwrite the null terminator
s[strlen(s)] = '0' + num%10;
}
}
Also, your function is assuming that s has enough space to hold all the digits, so you better make sure it does (INT_MAX is 10 digits long I think, so you need at least 11 characters).

Andrei Tita already showed you the problem you had with the NULL terminators. I will show you an alternative, so you can compare and contrast different approaches:
int intToStr(unsigned int num, char *s)
{
// We use this index to keep track of where, in the buffer, we
// need to output the current character. By default, we write
// at the first character.
int idx = 0;
// If the number we're printing is larger than 10 we recurse
// and use the returned index when we continue.
if(num > 9)
idx = intToStr(num / 10, s);
// Write our digit at the right position, and increment the
// position by one.
s[idx++] = '0' + (num %10);
// Write a terminating NULL character at the current position
// to ensure the string is always NULL-terminated.
s[idx] = 0;
// And return the current position in the string to whomever
// called us.
return idx;
}
You will notice that my alternative also returns the final length of the string that it output into the buffer.
Good luck with your coursework going forward!

Related

Write a recursive function to convert a given string into the number it represents

In this code, I want to convert the string into integer by using recursive function but it is giving output in negetive.
#include <iostream>
using namespace std;
int convert1(string s) {
if (s.length() == 1) {
int i = s[0] - '0';
return i;
}
int so = convert1(s.substr(0, s.length() - 1));
int num = s[s.length()] - '0';
int ans = so * 10 + num;
return (int)ans;
}
int main()
{
string s;
cin >> s;
cout << convert1(s) << endl;
}
If you try printing s[s.length()] each time you call convert1, you'll see that it's printing 0. And then you're subtracting the value of '0' (48) from that.
Let's say we try to convert "12".
The length is not 1, so we call convert1 on "1".
That is of length 1, so we return 1.
So, if so is 1, and s[s.length()] is 0, then num is -48 and so * 10 + num evaluates to 1 * 10 - 48 which is -38.
For a two digit number input, you will always see the first digit times 10, minus 48. For a three digit number, you'll see (the first digit * ten minus 48) times 10 minus 48. This pattern continues on. If the first digit is large enough, it times 10 minus 48 creates a positive number. If that's large enough, positive numbers continue to propagate through the recursion. If they ever get smaller than 48, then once the result is negative, it will just get larger as a negative number the more recursive calls are made.
As opposed to the way you have done things, you can employ an accumulator parameter in convert1.
int convert1(string s, int acc=0) {
if (s.length() == 1) {
return acc * 10 + (s[0] - '0');
}
return convert1(s.substr(1, s.length() - 1),
acc * 10 + (s[0] - '0'));
}
Each time the function is recursively called, we update the accumulator by multiplying it by ten and adding the value of the first digit, and update the string by taking the "tail" of the string.
Or better, but a little bit further from your original, we return the accumulator when the string is empty.
int convert1(string s, int acc=0) {
if (s.empty()) return acc;
return convert1(s.substr(1, s.length() - 1),
acc * 10 + (s[0] - '0'));
}
The benefit of this tail recursion is that this function (if properly optimized by a decent compiler) can run in constant stack space. Though it's academic in this case as the int type will overflow before a stack overflow.
The normal way
int main()
{
string s;
cin >> s;
cout << strtol(s.c_str(), nullptr, 10) << endl;
}
Recursive for some reason
int convert_string(const char* string, int length){
if (length == 0) {
return 0;
}
int output = string[0] - '0';
output *= pow(10, length - 1);
output += convert_string(&string[1], --length);
return output;
}
int main()
{
std::string s;
std::cin >> s;
std::cout << convert_string(s.c_str(), s.length()) << std::endl;
}
When you compute the last digit
int num = s[s.length()] - '0';
you have an out-of-bounds access to the string. Changing that to
int num = s[s.length() - 1] - '0';
and your code works. Inefficiently.
You create a new substring in every recursion. There are 2 ways to improve on that:
make a helper function that makes a copy of the string and then calls the recursive function. The recursive function takes a std::string & s and then can use s.pop_back(). As a side benefit the helper function can easily deal with strings starting with '-'. You should have this helper anyway.
change the argument to std::string_view then it's just a reference into the string and substring will just shrink that reference. The string is never copied. That's actually the only change, just change std::string to std::string_view and done.
I think the std::string_view is the way to go but requires c++17. Combine that with the helper for dealing with '-'.
The next thing is s[s.length() - 1], which can be written as s.back(). Safes a bit of typing and no risk of an off-by-one error.
Then your condition for terminating the recursion is overly complex. You can write
if (s.empty()) return 0;
instead at the cost of an extra recursion call. On the other hand this allows parsing "". Not sure which way is faster, the simpler test might balance the extra recursive call. I like it because it doesn't repeat the digit conversion code and is less to type.
Next, if you are using std::string_view, then the s.substr(0, s.length() - 1) expression can be changed to using s.remove_suffix(1);.
All combined this gives you:
int convert1(std::string_view s) {
if (s.empty()) return 0;
int num = s.back() - '0';
s.remove_suffix(1);
int so = convert1(s)
int ans = so * 10 + num;
return ans;
}
One more thing to consider but it's a complete rewrite of your algorithm:
Your recursion isn't tail recursive. This uses up stack space proportional to the length of the string. While for parsing an "int" this shouldn't be a problem it will be a problem for larger problems. Or if someone just enters a really big number "14654645656348756...65464".
To solve this you have to turn your algorithm around. Instead of chopping digits of at the end take them from the front like you would doing this iteratively:
int iterative_convert(const std::string &s) {
int acc = 0;
for (const auto c : s) acc = acc * 10 + (c - '0');
return acc;
}
To make this recursive you have to pass the intermediate result as accumulator down the recursion. So it becomes this:
int convert1(std::string_view s, int acc = 0) {
if (s.empty()) return acc;
acc = 10 * acc + (s.front() - '0');
return convert1(s.substr(1), acc);
}
Not sure how you came up with the back to front algorithm but front to back results in better code.
Note: Short of needing c++17, or if you prefer, you can also use std::string::const_iterator (requires passing s.cend() as extra argument) or good old const char *p = s.c_str();

Input C-style string and get the length

The string input format is like this
str1 str2
I DONT know the no. of characters to be inputted beforehand so need to store 2 strings and get their length.
Using the C-style strings ,tried to made use of the scanf library function but was actually unsuccessful in getting the length.This is what I have:
// M W are arrays of char with size 25000
while (T--)
{
memset(M,'0',25000);memset(W,'0',25000);
scanf("%s",M);
scanf("%s",W);
i = 0;m = 0;w = 0;
while (M[i] != '0')
{
++m; ++i; // incrementing till array reaches '0'
}
i = 0;
while (W[i] != '0')
{
++w; ++i;
}
cout << m << w;
}
Not efficient mainly because of the memset calls.
Note:
I'd be better off using std::string but then because of 25000 length input and memory constraints of cin I switched to this.If there is an efficient way to get a string then it'd be good
Aside from the answers already given, I think your code is slightly wrong:
memset(M,'0',25000);memset(W,'0',25000);
Do you really mean to fill the string with the character zero (value 48 or 0x30 [assuming ASCII before some pedant downvotes my answer and points out that there are other encodings]), or with a NUL (character of the value zero). The latter is 0, not '0'
scanf("%s",M);
scanf("%s",W);
i = 0;m = 0;w = 0;
while (M[i] != '0')
{
++m; ++i; // incrementing till array reaches '0'
}
If you are looking for the end of the string, you should be using 0, not '0' (as per above).
Of course, scanf will put a 0 a the end of the string for you, so there's no need to fill the whole string with 0 [or '0'].
And strlen is an existing function that will give the length of a C style string, and will most likely have a more clever algorithm than just checking each character and increment two variables, making it faster [for long strings at least].
You do not need memset when using scanf, scanf adds the terminating '\0' to string.
Also, strlen is more simple way to determine string's length:
scanf("%s %s", M, W); // provided that M and W contain enough space to store the string
m = strlen(M); // don't forget #include <string.h>
w = strlen(W);
C-style strlen without memset may looks like this:
#include <iostream>
using namespace std;
unsigned strlen(const char *str) {
const char *p = str;
unsigned len = 0;
while (*p != '\0') {
len++;
*p++;
}
return len;
}
int main() {
cout << strlen("C-style string");
return 0;
}
It's return 14.

pointer cannot maintain in c++ function

void concat(char *str, char *ch, int num)
{
*str= *ch; ++str;
while (num>0) {
*str = '0' + num % 10;
num /= 10;
++str;
}
}
concat(runner, 'a', 10);
concat(runner, 'b', 20);
i just want to concat one character like 'a' to 10, the expected result will be a10
the first line works fine. but i just thinking after the first line(concat a10), the runner should point to the end of string, so when i run the second line, it should be a10b20, but actual result is b20 overwrite the a10.
i think it should be pointer problem , can you help me.
I'm changing my answer altogether. Put this in the beginning of your function:
void concat(char * str, const char * ch, int num) {
while (*str) {
++str;
}
Then keep the rest the same. This is really what concat should look like. Just make sure that runner[0] == 0 before calling it the first time! And add the following code to the end of your function, before the final brace:
*str = 0;
}
using & should be ok
or actually in c, you can use **, two ways.
Well, the code does what you ask of it.
For this to work you need to find the end of the first string and then add to it:
void concat(char *str, char *ch, int num)
{
str += strlen(str); /* make sure we start adding at the end of str */
*str= *ch; ++str;
while (num>0) {
*str = '0' + num % 10;
num /= 10;
++str;
}
}
But now you must make sure str[0] is 0 at the beginning
Because every time concat is called, the index of str starts from 0. That's why the content of str is overwritten. Just skip all the filled positions in str before you append any to it.
The problem is that your function is not aware of the end of the string being passed in. To fix this you will need to intialize your char * to all 0's or \0. The other issue is you are converting your number to characters incorrectly. And finally there is nothing safe about the function since the size of the string is not passed in so you just have to make sure you allocate enough space before hand.
void concat(char *str, const char *ch, int num)
{
//This is function not safe since you do not
//know how much space str has allocated
str += strlen(str);
*str = *ch; ++str;
if(num < 0)
{
*str = '-';//Add the -
++str;
num *= -1; //Make the number positive
}
//Determine the number of digits first
//because you need to add characters backwards
int digits = 0, tmpnum = num;
while (tmpnum) {
tmpnum /= 10;
++digits;
}
while(digits--)
{
str[digits] = '0' + num % 10;
num /= 10;
}
}
Usage:
char *runner = new char[20]();
//or
//char *runner = (char*)calloc(20, 1);
concat(runner, "a", 10);
concat(runner, "b", 20);
concat(runner, "c", -30);
delete [] runner;
//or if you used calloc
//free(runner);
I did this assuming this was a homework assignment, there are easier/safer ways to accomplish this especially using C++ which is what your question was tagged.

loop logic, encrypting array C++

I am trying to perform some operations on an array which the final goal is to do a simple encryption. But anyways my array is 458 characters long which consists of mostly letters and some commas, periods, etc. I am trying to start from last character of array and go to the first character and uppercase all the letters in the array. It reads the last character "" correctly, but then the next step in the for loop is like 4 characters over and skipped a few letters. Is something wrong with my control logic?
void EncryptMessage (ofstream& outFile, char charArray[], int length)
{
int index;
char upperCased;
char current;
for (index = length-1; index <= length; --index)
{
if (charArray[index] >= 'A' && charArray[index] <= 'Z')
{
upperCased = static_cast<char>(charArray[index]);
current = upperCased;
outFile << current;
}
else
{
charArray[index]++;
current = charArray[index];
}
}
}
Change:
for (index = length-1; index <= length; --index)
to:
for (index = length-1; index >= 0; --index)
In the else leg of your if statement, you're setting the value of current, but never writing it out, so all that gets written out are what start as capital letters (and, as others have pointed out, your loop condition isn't correct).
If I were doing this, I'd structure it a bit differently. I'd write a small functor to encrypt a single letter:
struct encrypt {
char operator()(char input) {
if (isupper(input))
return input;
else
return input+1;
}
};
Then I'd put the input into an std::string, and operate on it using std::transform:
std::string msg("content of string goes here.");
std::transform(msg.rbegin(), msg.rend(),
std::ostream_iterator<char>(outFile, ""),
encrypt());

How to read in a string of Numbers into an array

I am working on a programming assignment in which we are making our own BigNum class. One of the constructors needs to be set up so that it can take a number from a string (i.e. 342567) and reads it into an array. However if the number were 0000000342567 it would have to be able to skip over the 0s and just read 342567.
Where is what i have so far but am lost on trimming the 0s
BigNum::BigNum(const char strin[])
{
size_t size = strlen(strin);
positive = true;
capacity = size;
digits = new size_t[capacity];
used=0;
while(used<size)
{
if(strin[size - used -1] =='-')
{
positive = false;
size --;
}
else if(strin[size - used -1] =='+')
{
size --;
}
else
{
digits[used] = strin[size - used -1] - '0';
used++;
}
}
}
Here is the assignment description if it helps
http://csel.cs.colorado.edu/%7Eekwhite/CSCI2270Fall2011/hw2/Homework2.pdf
Here's a hint:
Write a separate loop at the beginning that skips over all the zeros.
Add this just before your while loop:
for (int i=0; i < size; i++)
{
if (strin[i] >= '1' && strin[i] <= '9')
{
used = i;
break;
}
}
This way, your while loop begins reading the string only from the index where the number actually begins, skipping over all leading 0s.
This should handle the leading sign as well:
BigNum::BigNum(const char strin[])
{
size_t size = strlen(strin);
positive = true;
used=0;
if (strin[0] == '+' || strin[0] == '-')
{
//set positive or negative
used++;
}
while (used < size)
{
if (strin[used] != '0')
break;
used++; //used will only increment if above if condition failed.
}
int digitIndex = 0;
digits = new size_t[size-used]; //create digits array here so it isn't larger than needed
while(used<size)
{
digits[digitIndex++] = strin[used++];
}
}
You just need to add another while loop before the one you have.
But just some other hints:
You can't change the sign of the number at any digit, the sign depends only on the very first charachter. So if you had a string like -2345, that'll be ok, but if you had something other like: 234-88 then this should be invalid, what will you do with this then?
Also the digits array shouldn't really be equal to size, but rather should drop the sign digit if it did exist, so how will you deal with capacity?
Hope that's helpful!