Возникло необработанное исключение: нарушение доступа для чтения. x было 0x20B4112

#c

#c

Вопрос:

 using namespace std;

float str_to_float(char x[]) {
    int j;
    float val1 = x[0] - '0';
    float val2=0,factor=1;
 
    for (int i = 1; x[i] != '.'; i  ) {
        val1 = (val1 * 10)   (x[i] - '0'); 
        j = i;
    }
    for (int k = j   2; k != ''; k  ) {
        **val2 = val2   (x[k] - '0')*factor;**
        factor /= 10;
    }
    return val1 val2;
    }

int main() {
    char x[1000];
    cin.getline(x, 1000);
    cout<<str_to_float(x);
    return 0;
}
 

Эта функция должна возвращать значение с плавающей запятой строки, содержащей число с плавающей запятой.
При отладке «нарушения доступа для чтения» в строке, выделенной жирным шрифтом (во втором цикле for), возникает ошибка

Комментарии:

1. k != '' На самом деле вы не хотите сравнивать индекс в массиве со значением char из массива.

2. Какое значение будет j иметь x[1] десятичная точка (например, если пользователь вводит 1.23 )?

3. Как вы думаете, что будет делать первый цикл, если строка вообще не содержит десятичной точки? Например "2" .

4. С точки зрения стиля, вам не нужно i и k . Просто используйте j в качестве управляющей переменной цикла в обоих циклах. Таким образом, вам не нужно копировать значения вокруг: for (j = 1; x[j] != ‘.’; j) , затем между двумя циклами увеличивайте j значение после десятичной точки j; , а затем запускайте второй цикл for ( ; x[j] != ‘’; j) .

5. Кроме того, эти повторяющиеся деления на 10 приводят к накоплению ошибок округления. Вы получите более точный результат, если просто сложите цифры справа от десятичной запятой в виде целого значения, как и в первом цикле, затем разделите на std::pow(10, n) , где n — количество цифр, которые вы видели.

Ответ №1:

Есть 2 ошибки:

  1. Для второго цикла измените условие на x[k] != '' .
  2. Переменная factor должна быть инициализирована 0.1 .

Кроме того, чтобы избежать некоторых ошибок во время выполнения (например, в случае 0.908), запустите первый цикл из index 0 , чтобы переменная j имела допустимое значение перед запуском второго цикла.

Взгляните на следующую реализацию:

 #include <iostream>
#include <iomanip>

double str_to_double(char x[]) {
    
    int j;
    double val1 = 0, val2 = 0.0, factor = 0.1;
    
    for (int i = 0; x[i] != '.'; i  ) {
        val1 = (val1 * 10)   (x[i] - '0'); 
        j = i;
    }
    for (int k = j   2; x[k] != ''; k  ) {
        val2 = val2   (x[k] - '0')*factor;
        factor /= 10;
    }
    return val1 val2;
}

int main() {
    char x[1000];
    std::cin.getline(x, 1000);
    std::cout<<std::setprecision(15)<<str_to_double(x);
    return 0;
}
 

Тестовые примеры:

  1. Тестовый пример 1: ввод: 34.908 , вывод: 34.908
  2. Тестовый пример 2: ввод: 0.908 , вывод: 0.908
  3. Тестовый пример 3: ввод: 000006795.989090877700000 , вывод: 6795.9890908777

PS: При больших значениях float и double может быть потеря точности. Прочитайте эту статью.