Почему оператор возврата функции не является обычным int [] - PullRequest
2 голосов
/ 26 мая 2019

Я только начал использовать Dlang, и он кажется идеальным для людей, которые хотят более безопасный язык Си. Кроме того, он имеет современные парадигмы, такие как функциональное программирование.

Я пытаюсь следующий код для преобразования списка чисел в виде строк в список целых чисел:

import std.stdio; 
import std.array;
import std.conv;

int[] list_str2int(char[][] slist){     // this function should convert a list of numbers as char[] to integers
    int[100] intcol; 
    int N = cast(int)slist.length; 
    foreach(int i; 0..N){
        char[] temp = slist[i];
        temp = split(temp, ".")[0];   // effectively this is floor; to!int does not work if '.' is there; 
        intcol[i] = to!int(temp);   // not working; 
    }
    return intcol;                  // error from this statement; 
}

void main(){
    char[][] strlist = cast(char[][])["1.1","2.1","3.2","4.4"]; 
    int[] newintlist = list_str2int(strlist); 
    writeln("Converted list: ", newintlist); 
}

Но получаю следующую ошибку:

$ rdmd testing.d 

testing.d(13): Error: returning cast(int[])intcol escapes a reference to local variable intcol
Failed: ["/usr/bin/dmd", "-v", "-o-", "testing.d", "-I."]

Я не могу понять, почему произошла ошибка в строке возврата первой функции, где переменная int [].

Где проблема и как ее можно решить? Спасибо за вашу помощь.

Ответы [ 2 ]

6 голосов
/ 26 мая 2019

int[100] является статическим массивом (тип значения) и расположен в фрейме стека list_str2int - поэтому он прекратит свое существование после возврата из функции. Возвращаемое значение функции int[] представляет собой фрагмент (ссылочный тип), который не содержит никаких данных, но ссылается на непрерывное число целых чисел где-то в памяти. Таким образом, оператор return intcol; принимает фрагмент статического массива, однако возвращать его недопустимо, поскольку этот фрагмент будет указывать на память, которая больше не будет действительной после возврата из функции.

У вас есть несколько вариантов:

  • Объявите также тип возвращаемого значения int[100]. Делая это типом значения, целые числа будут скопированы в кадр стека вызывающей стороны.

  • Выделите массив в куче программы, объявив и инициализировав массив как auto intcol = new int[100];. Это сделает intcol кусочек памяти в куче. Память в куче принадлежит сборщику мусора и фактически имеет бесконечное время жизни.

  • Опция, которая отличается от описанной выше, но более идиоматична для современного D, заключается в использовании диапазонов. Ваша программа может быть переписана в одно утверждение следующим образом:

    import std.algorithm.iteration;
    import std.stdio; 
    import std.array;
    import std.conv;
    
    void main()
    {
        ["1.1", "2.1", "3.2", "4.4"]
            .map!(item => item
                .split(".")[0]
                .to!int
            )
            .array // optional, writeln and co can write ranges
            .writefln!"Converted list: %s";
    }
    
3 голосов
/ 26 мая 2019

int[] - это фрагмент, он может использовать динамическое распределение.

int[100] - это массив из 100 элементов.Он расположен в стеке

Как и в C, вы не можете вернуть локальную память из функции, вы не можете вернуть intcol, так как память за ней становится недействительной после возврата из функции.

Мне кажется неизвестным, хотите ли вы использовать динамические массивы или статические.Если вы хотите использовать динамические массивы, то придерживайтесь их.

import std.stdio; 
import std.array;
import std.conv;

int[] list_str2int(char[][] slist){     // this function should convert a list of numbers as char[] to integers
    int N = cast(int)slist.length; 
    int[] intcol = new int[N];
    foreach(int i; 0..N){
        char[] temp = slist[i];
        temp = split(temp, ".")[0];   // effectively this is floor; to!int does not work if '.' is there; 
        intcol[i] = to!int(temp);   // not working; 
    }
    return intcol;                  // error from this statement; 
}

void main(){
    char[][] strlist = cast(char[][])["1.1","2.1","3.2","4.4"]; 
    int[] newintlist = list_str2int(strlist); 
    writeln("Converted list: ", newintlist); 
}

выведет:

 Converted list: [1, 2, 3, 4]
...