I'm trying to understand Rust' memory mechanism, especially how it works when you need it to interoperate with C code.
Here I have small C code represents a linked list and a function prints its attr to stdout:
// this is wrapper.h
typedef struct elem {
int attr;
struct elem *next;
} elem;
typedef struct wrapper {
char name[16];
struct elem *first_elem;
} wrapper;
void print_all_attrs(wrapper *w);
// -----
// and this is how wrapper.c looks like:
#include <stdio.h>
#include "wrapper.h"
void print_all_attrs(wrapper *w) {
printf("NAME = %s\n", w->name);
elem *elem = w->first_elem;
while(elem != NULL) {
printf("ATTR = %d\n", elem->attr);
elem = elem->next;
}
}
We all know how to prepare a wrapper that can hold a linkedlist of elem which is created dynamically: we need to create a wrapper variable, then a logic allocates an area in heap for every elem, assigns the first one into wrapper->first_elem and then others to previous' next pointer. here the code does exactly same thing:
void main() {
wrapper w = {
.name = "ABCD",
};
elem *prev = NULL;
for(int i=0; i<10; i++) {
elem *new = malloc(sizeof(elem));
new->attr = i;
if(w.first_elem == NULL) {
w.first_elem = new;
prev = new;
continue;
}
prev->next = new;
prev = prev->next;
}
print_all_attrs(&w);
// CLEARING HEAP STUFF HERE...
}
So, in Rust, I'm trying to use those definitions by generating code bindgen and cc libraries, I'm skipping these details right now.
If I want to allocate something into heap, I know I can use Box but it doesn't work at all because it drops when it goes out scope. take a look below code that exits with segmentation fault:
unsafe {
let mut prev: *mut xxx::elem = w.first_elem;
for n in 0..10 {
let mut elem = Box::new(xxx::elem {
attr: n,
next: ptr::null_mut(),
});
if w.first_elem.is_null() {
w.first_elem = &mut *elem;
prev = &mut *elem;
continue;
}
(*prev).next = &mut *elem;
prev = (*prev).next;
}
xxx::print_all_attrs(&mut w);
}
I managed to use Layout and alloc, but these guys bring a cost that I need to dealloc the things after use:
unsafe {
use std::alloc::{Layout, alloc};
let mut prev: *mut xxx::elem = w.first_elem;
for n in 0..10 {
let layout = Layout::new::<xxx::elem>();
let mut p = alloc(layout) as *mut xxx::elem;
(*p).attr = n;
(*p).next = ptr::null_mut();
if w.first_elem.is_null() {
w.first_elem = p;
prev = p;
continue;
}
(*prev).next = p;
prev = (*prev).next;
}
xxx::print_all_attrs(&mut w);
// dealloc stuff here.
}
I wonder that if there is another possible way to do that without using Layout and its friends? I see this is one of the proper way to make it but it makes me feel this is not the expected "Rust-way".
Related
I have currently been dabbling in the Rust programming language and decided a good way to test my skills was to program an application that would find the median of any given list of numbers.
Eventually I got into the Final stretch of code and stumbled into a problem.
I needed to parse an f64 variable into a usize variable.
However, I don't know how to go about doing this (Wow what a surprise!).
Take a look at the second function, calc_med() in my code. The variable n2 is supposed to take n and parse it into a usize. The code is not finished yet, but if you can see any more problems with the code please let me know.
use std::io;
use std::sync::Mutex;
#[macro_use]
extern crate lazy_static;
lazy_static! {
static ref v1: Mutex<Vec<f64>> = Mutex::new(Vec::new());
}
fn main() {
loop {
println!("Enter: ");
let mut inp: String = String::new();
io::stdin().read_line(&mut inp).expect("Failure");
let upd_inp: f64 = match inp.trim().parse() {
Ok(num) => num,
Err(_) => if inp.trim() == String::from("q") {
break;
} else if inp.trim() == String::from("d"){
break
{
println!("Done!");
calc_med();
}
} else {
continue;
}
};
v1.lock().unwrap().push(upd_inp);
v1.lock().unwrap().sort_by(|a, b| a.partial_cmp(b).unwrap());
println!("{:?}", v1.lock().unwrap());
}
}
fn calc_med() { // FOR STACKOVERFLOW: THIS FUNCTION
let n: f64 = ((v1.lock().unwrap().len()) as f64 + 1.0) / 2.0;
let n2: usize = n.to_usize().expect("Failure");
let median: f64 = v1[n2];
println!("{}", median)
}
I have a simple exercise in Coderbyte, it just want to have a function that's WordSplit(strArr) read the array of strings stored in strArr, For example I have two elements like ["hellocat", "apple,bat,cat,goodbye,hello,yellow,why"]
I just want to to determine if the first element in the input can be split into two words, where both words exist in the dictionary that is provided in the second input.
For example: the first element can be split into two words: hello and cat because both of those words are in the dictionary.
So the program should return the two words that exist in the dictionary separated by a comma, as this result hello,cat .
I've made a recursive solution below. It checks if the string to be split starts with any word in the dictionary. If it exists, the function is called again using a substring with that first word removed.
This function only works up to the first word that isn't in the dictionary since you did not specify the expected behavior when the inputted word is not made up of words in the dictionary. You could make it throw an exception perhaps, but please specify your expectation.
void main() {
print(wordSplit(["hellocat", "apple,bat,cat,goodbye,hello,yellow,why"]));
//hello,cat
}
String wordSplit(List<String> arg) {
String wordToSplit = arg[0];
String dict = arg[1];
List<String> parsedDict = arg[1].split(',');
for(String word in parsedDict) {
if(wordToSplit.startsWith(word)) {
//If the substring would be empty, don't do more recursion
if(word.length == wordToSplit.length) {
return word;
}
return word + ',' + wordSplit([wordToSplit.substring(word.length), dict]);
}
}
return wordToSplit;
}
#include <bits/stdc++.h>
using namespace std;
vector<string> converToWords(string dict) {
vector<string> res;
string s = "";
int n = dict.length();
for(int i=0; i<n; i++) {
if(dict[i] == ',') {
res.push_back(s);
s = "";
}
else s += dict[i];
}
res.push_back(s);
s = "";
return res;
}
string solve(string str[]) {
string result = "";
string word = str[0], dict = str[1];
int n = word.length();
vector<string> vs = converToWords(dict);
unordered_set<string> ust;
for(auto it: vs) ust.insert(it);
// for(auto i=ust.begin(); i!=ust.end(); i++){
// cout<<*i<<endl;
// }
string s = "";
for(int i=0; i<n; i++) {
s += word[i];
// cout<<s<<endl;
string temp = word.substr(i+1, n-(i+1));
// cout<<temp<<endl;
if(ust.find(s) != ust.end() && ust.find(temp) != ust.end()) {
cout<<s<<endl;
cout<<temp<<endl;
result += s+","+temp;
break;
}
temp = "";
}
return result;
}
int main() {
string arr[2];
cin>>arr[0]>>arr[1];
cout << solve(arr);
return 0;
}
I have this function:
use std::io;
pub fn recv(mut buf: &mut [u8]) -> io::Result<usize> {
let size_to_extend = 50; // I want to increase the size of "buf" by 50
unsafe {
/* ??? */
}
}
How can I adjust the size of the array buf, even though it's a parameter? It is necessary that this method needs to happen.
What you are attempting to do is all-but-guaranteed to cause undefined behavior. Find a better API.
If you want the changes to be reflected outside of the function, you are out of luck. There's no way that this function signature will allow for that to happen, for the same reason that fn foo(x: i32) won't allow you to change the value passed in as observed by the caller.
If you just need this inside of the function, use slice::from_raw_parts. I've marked the entire function as unsafe because certain inputs will cause undefined behavior and this code cannot possibly guard against it:
use std::slice;
pub unsafe fn recv(buf: &mut [u8]) {
let size_to_extend = 50;
let ptr = buf.as_mut_ptr();
let len = buf.len();
let bad_idea = slice::from_raw_parts_mut(ptr, len + size_to_extend);
for b in bad_idea.iter_mut() {
*b = 10;
}
}
If you can change the API, something like this works to expose the change outside the function:
pub unsafe fn recv(buf: &mut &mut [u8]) {
let size_to_extend = 50;
let ptr = buf.as_mut_ptr();
let len = buf.len();
let bad_idea = slice::from_raw_parts_mut(ptr, len + size_to_extend);
for b in bad_idea.iter_mut() {
*b = 10;
}
*buf = bad_idea;
}
See also:
How can I get an array or a slice from a raw pointer?
I am playing around with F# and wanted to check how it generates code compared to C# and found a strange line.
I am using dotTrace to decompile code and make C# equivalent. I have also tried to check IL code using LinqPad.
My code is quite small.
open System
[<EntryPoint>]
let main argv =
let mutable sum = 0
// 1000 or 997
//let arr : int array = Array.zeroCreate 997
//let arr = Enumerable.Range(0, 997).ToArray()
let arr :int array = [|0..997|]
arr |> Array.iter (fun x -> sum <- sum + x)
printfn "%i" sum
0
And this is what I get.
{
int func = 0;
int[] numArray = SeqModule.ToArray<int>(Operators.CreateSequence<int>(Operators.OperatorIntrinsics.RangeInt32(0, 1, 997)));
if ((object) numArray == null)
throw new ArgumentNullException("array");
int length = numArray.Length;
int index = 0;
int num1 = length - 1;
if (num1 >= index)
{
do
{
int num2 = numArray[index];
func += num2;
++index;
}
while (index != num1 + 1);
}
PrintfModule.PrintFormatLineToTextWriter<FSharpFunc<int, Unit>>(Console.Out, (PrintfFormat<FSharpFunc<int, Unit>, TextWriter, Unit, Unit>) new PrintfFormat<FSharpFunc<int, Unit>, TextWriter, Unit, Unit, int>("%i")).Invoke(func);
return 0;
}
}
And this is how IL looks like.
// IL_0019: stloc.1 // 'numArray [Range(Instruction(IL_0019 stloc.1)-Instruction(IL_0040 ldloc.1))]'
// IL_001a: ldloc.1 // 'numArray [Range(Instruction(IL_0019 stloc.1)-Instruction(IL_0040 ldloc.1))]'
// IL_001b: box int32[]
// IL_0020: brfalse.s IL_0025
// IL_0022: nop
// IL_0023: br.s IL_0030
// IL_0025: ldstr "array"
// IL_002a: newobj instance void [mscorlib]System.ArgumentNullException::.ctor(string)
// IL_002f: throw
Compiled using Release, .Net 4.6, FSharp.Core 4.4.0.0, Optimize code, Generate Tail Calls.
I am very curious about the NULL check and cast.
(object) numArray == null
I do understand why the obj cast is done. The array is not a null and can't be checked without.
I am curious (don't thinks it is a problem) and the question is more about compiler.
Why would it be useful to check for null? I am not defining an option type.
Under what conditions the exception will fire.
That check is part of the implementation of Array.iter. The compiler just seems not to be smart enough to figure out that box arg in this case is never going to be null.
say i have the following two struct definitions in C.
struct child {
int x;
};
struct Yoyo {
struct child **Kids;
};
How would i go about allocating the memory for Kids.
say for example i have some function Yoyo_create().
static struct Yoyo * yoyo_create() {
int n = 32000;
struct Yoyo *y;
y = malloc(sizeof( *Yoyo));
y->Kids = malloc(n*sizeof(*Child));
for (i = 0 ; i < n ; i ++) { y->Kids[i] = NULL; }
}
and then to destroy the Kids in some "destructor function" i would do.
void yoyo_destroy(struct yoyo *y)
{
free(y->Kids);
free(y);
}
Does that make sense?
you don't need these lines
y->Kids = malloc(n*sizeof(*Child)); and <br>
free(y->Kids);
because your y contains kids structure in it. And except these , you are going well
y = malloc(sizeof(struct Yoyo));
y->Kids = malloc(n*sizeof(struct Child));