С++ Написать функцию, которая считает сумму символьных строк (char)!
Задание: Написать функцию на языке C++, которая считает сумму чисел, когда пользователь вводит их с клавиатуры. Например, пользователь вводит число 12, а затем 32, функция делает подсчет и после вызова функции на экран выводится ответ = 44.
Числа, которые пользователь вводит с клавиатуры заносятся в массивы с типом char, полученный результат после подсчетов в функции также должен быть занесен в массив типа char.
Я написала функцию, которая выполняет все эти действия, вот мой код:
#include <iostream>
#include <string.h>
using namespace std;
const int n = 100;
void summ(char* a, char* b, char* c) {
int a_len = strlen(a), b_len = strlen(b);
int a_tmp = a_len - 1, b_tmp = b_len - 1, tmp, r = 0, digit;
for (int i = 0; i < max(a_len, b_len) + 1; ++i) {
tmp = ((a[a_tmp] - '0') + (b[b_tmp] - '0')) + r;
if (b_tmp < 0)
tmp = (a[a_tmp] - '0') + r;
if (a_tmp < 0)
tmp = (b[b_tmp] - '0') + r;
if (tmp > 9) {
digit = tmp % 10;
c[i] = digit + '0';
r = 1;
}
else {
r = 0;
c[i] = tmp + '0';
}
a_tmp--;
b_tmp--;
}
}
int main() {
int T;
char a[n];
char b[n];
char c[n];
do {
cin >> a;
cin >> b;
summ(a, b, c);
for (int i = strlen(c) - 1; i >= 0; --i) {
cout << c[i];
}
cout << "\nПродолжить - 1, закончить - 0." << endl;
cin >> T;
} while (T == 1);
}
С целыми положительными цифрами все работает, но есть проблема, в моем задании мне нужно, чтобы функция считала еще и сумму отрицательных чисел, также записывая их в массив, например, пользователь вводит 34 и -11, функция должна посчитать ответ = 23.
Помогите, пожалуйста, уже неделю мучаюсь с этим заданием, а в голову так и не приходит как это реализовать..
Ответы (2 шт):
Ну все тривиально - дам пример на строке (ввод организуйте сами)
Алгоритм такой :
- разбиваем строку на токены
- парсим токены на числа (мало ли кто то введет бяку) и дампим в вектор
- делаем акум
Остальное обернете сами)
вот пример кода
ВАЖНО: максимальное число обусловлено лимитом std::stoi +-2,147,483,647
#include <iostream>
#include <numeric>
#include <regex>
#include <string>
#include <vector>
std::vector<std::string> SeparateLineToWordsByRegexp(std::string line) {
std::regex words_regex("[^\\s,;]+");
auto words_begin =
std::sregex_iterator(std::begin(line), std::end(line), words_regex);
auto words_end = std::sregex_iterator();
std::vector<std::string> words;
for (std::sregex_iterator i = words_begin; i != words_end; ++i) {
words.push_back((*i).str());
}
return words;
}
std::vector<int64_t> PickIntsFromStringVector(std::vector<std::string> words) {
std::vector<int64_t> ret;
for (const auto &word : words) {
if (word.find_first_not_of("-0123456789.") == std::string::npos) {
ret.push_back(std::stoi(word));
}
}
return ret;
}
int main() {
std::string line{"1 2 3 4 11 19"};
auto words{SeparateLineToWordsByRegexp(line)};
auto dig_vector{PickIntsFromStringVector(words)};
auto ret{std::accumulate(std::begin(dig_vector), std::end(dig_vector), 0)};
std::cout << "ret is : " << ret << std::endl;
return 0;
}
Всего существуют 4 ситуации с учетом + и - их можно разделить на два типа:
- сложение:
-a + -bиa + b - вычитание:
a + -bи-a + b
Поэтому код можно унифицировать работая с числами по |модулю| инвертировав результат при необходимости получить отрицательное значение:
a < 0 && b < 0тогдаa + bотрицательное число|a| > |b| && a < 0или|a| < |b| && b < 0тогдаa + bотрицательное число
Что касается переносимого отстатка, то он считается по разному в зависимости от того складываем ли мы либо отнимаем:
- при сложении либо
0либо1 - при вычитании либо
0либо-1
Для правильного вычитания мы должны его производить из большего по модулю, поэтому я добавил функцию is_a_gt_or_equal_b которая определяет какое из чисел больше сравнвая их строчные представления (- тоже учитывается, но данном случае в нем нет необходимости так как передаются аргументы по модулю)
Одним из интересных моментов был момент когда я получал:
- вместо
9символ/ - вместо
1символ'
Не долго думая я понял что это смещение от '0' влево чего быть не должно, поэтому я прибавлял 10 для того чтобы:
- смещение из
-9стало1 - смещение из
-1стало9
C учетом того что я заполняю результирующую строку с конца а не с начала, мне нет необходимости делать цикл для вывода числа достаточно лишь обрезать буфер до нужной длины, это делает функция get_tail она же убирает из числа ведущие нули если они вдруг появились:
123+-100=023
Чтобы не гонять лишний раз циклы я делаю сравнение чисел в самом начале не дадут ли они 0 логика простая (возможно можно проще):
'-'+a==b'-'+b==a
В ходе написания кода мне очень помогли тесты, для краткости я их не включил в этот код. Но я оставил некоторые комментарии в основном ввиде выражений чтобы было понятна цель проверки или условия.
Если будут предложения по оптимизации кода с удовольствием почитаю (давно не писал на плюсах). Если возникнут вопросы на которые я не ответил выше, так же готов ответить.
полный код:
#include <iostream>
#include <string.h>
using namespace std;
const int n = 100;
inline int get_digit( char c ) { return c - '0'; }
inline bool is_negative( char * c ){ return c[0] == '-'; }
inline void get_abs( char * c, char * h ){
sprintf( h, &c[is_negative( c )? 1 : 0], strlen(c) );
}
inline void get_neg( char * c, char * h ){
sprintf( h, "-%s", &c[is_negative( c ) ? 1 : 0] );
}
inline void set_neg( char * c ){
char t[n];
get_abs( c, t );
get_neg( t, c );
}
bool is_sum_zero ( char * a, char * b ){
string tempA = a;
string tempB = b;
return '-' + tempA == tempB
|| '-' + tempB == tempA;
}
void get_tail( char* c, int size ){
int len = strlen( c );
memcpy( c, c + (len-size) , size + 1 );
int i = 0; // убираем ведущие нули
while( c[i]=='0' && i < n - 1 ){ i++; }
if (i){ memcpy(c, c + i , size + 1 - i); }
}
bool is_a_gt_or_equal_b( char *a, char *b ){
int len_a = strlen( a ),
len_b = strlen( b );
bool bNeg = is_negative( b ),
aNeg = is_negative( a );
if ( len_a > len_b && !aNeg ) return true; // 10000 > -10 || 100000 > 10
if ( len_a < len_b && bNeg ) return true; // -10 > -10000 || 10 > -10000
if ( len_a > len_b && ( !bNeg && !aNeg ) ) return true; // 1 > 10000
if ( len_a < len_b && ( !bNeg && !aNeg ) ) return false; // -1 > -10000
int i = aNeg ? 1 : 0;
while( i != len_a ){
if ( get_digit( a[i] ) != get_digit( b[i] ) ){
return get_digit( a[i] ) >= get_digit( b[i] ) ? !aNeg : aNeg;
}
i++;
}
return true;
}
int exract_digit( char *c, int &pos ){
if (pos >= 0) {
int d = get_digit( c[pos--] );
return d;
}
return 0;
}
void summ( char* a, char* b, char* c ){
enum {POSPOS, NEGPOS, POSNEG, NEGNEG};
if (is_sum_zero( a, b )){ // a + b = 0
sprintf(c, "%d", 0);
return;
}
char mod_a[n],
mod_b[n];
get_abs(a, mod_a);
get_abs(b, mod_b);
bool bNeg = is_negative( b ),
aNeg = is_negative( a );
int c_len = strlen( c ),
a_tmp = strlen( mod_a ) - 1,
b_tmp = strlen( mod_b ) - 1,
tmp = c_len - 1,
r = 0,
digitA = 0,
digitB = 0,
cs = (bNeg * 2 + aNeg);
switch( cs ){
case POSPOS: // ++
case NEGNEG: // --
while ( a_tmp > -1 || b_tmp > -1 || r ){
digitA = exract_digit( mod_a, a_tmp );
digitB = exract_digit( mod_b, b_tmp );
int sm = digitA + digitB + r;
r = sm >= 10 ? 1 : 0;
c[tmp] = (sm % 10) + '0';
tmp--;
}
get_tail( c, (c_len-tmp) - 1 );
if ( cs == NEGNEG ){ // --
set_neg( c );
}
return;
break;
case NEGPOS: // -+
case POSNEG: // +-
bool isAgtB = is_a_gt_or_equal_b( mod_a, mod_b );
while ( a_tmp > -1 || b_tmp > -1 || r ){
digitA = exract_digit( mod_a, a_tmp );
digitB = exract_digit( mod_b, b_tmp );
int sm = ( isAgtB ? ( digitA - digitB ) : ( digitB - digitA ) ) + r;
r = sm < 0 ? -1 : 0;
if ( sm < 0 ) sm += 10; // ' --> 1 && / --> 9
c[tmp] = ( sm % 10 ) + '0';
tmp--;
}
get_tail( c, c_len - tmp - 1);
if ( !isAgtB && cs != NEGPOS || isAgtB && cs == NEGPOS ){ // 7 - 9 || -9 + 7
set_neg( c );
}
return;
break;
}
}
bool is_number(char * c){
int len = strlen(c);
bool is_neg = is_negative(c);
for( int i = is_neg ? 1 : 0; i < len; ++i ){
if( !( c[i] >= '0' && c[i] <= '9') ){
return false;
}
}
return true;
}
int main() {
int T;
char a[n];
char b[n];
char c[n];
do {
cout << "a:";
cin >> a;
cout << "b:";
cin >> b;
if(is_number(a) && is_number(b)){
summ(a, b, c);
cout << "Результат:" << c << endl;
} else {
cout << "Введите два числа" << endl;
T = 1;
continue;
}
cout << "\nПродолжить - 1, закончить - 0." << endl;
cin >> T;
} while (T == 1);
}