I'm working on some coding challenges in Rust and one of the problems is to determine if a phrase is a pangram. I have seen the following implementation:
// Copy chars into a vector, sort and remove duplicates
let mut chars: Vec<char> = pangram.chars().collect();
chars.sort();
chars.dedup();
This solution, however, is O(nlogn) time because of the sort. I can do it in O(n) time, but I'm running into a problem.
Below is the code I've tried to write:
fn is_pangram(s: String) -> bool {
let mut num_seen = 0;
let mut seen: [bool; 26] = [false; 26];
for c in s.to_lowercase().as_bytes() {
// ASCII 10 is newline character
if c as usize == 10 {
break;
}
// Lowercase ASCII is 97 to 122
if !seen[122 - c as usize] {
seen[122 - c as usize] = true;
num_seen += 1;
}
}
return num_seen == 26;
}
I'm getting the following errors:
18:55 $ rustc pangram.rs
pangram.rs:10:12: 10:22 error: casting &u8 as usize is invalid
pangram.rs:10 if c as usize == 10 {
pangram.rs:10:12: 10:22 help: cast through a raw pointer first
pangram.rs:14:24: 14:34 error: casting &u8 as usize is invalid
pangram.rs:14 if !seen[122 - c as usize] {
pangram.rs:14:24: 14:34 help: cast through a raw pointer first
pangram.rs:15:24: 15:34 error: casting &u8 as usize is invalid
pangram.rs:15 seen[122 - c as usize] = true;
pangram.rs:15:24: 15:34 help: cast through a raw pointer first
error: aborting due to 3 previous errors
I've tried casting c as *mut usize and c as *const usize, but neither worked. How many I make this work?
It's a very simple changeāa single character, in fact:
for &c in s.to_lowercase().as_bytes() {
^
You're trying to treat a reference (which is what as_bytes results in) as a regular value, which doesn't work.
You could either do what I did above (change for c in to for &c in) or replace all occurrences of c inside of the for loop with *c; they essentially do the same thing.
Related
I believe I am having a problem with both the data type and ownership of iter. It is first declared inside the for loop expression. I believe Rust infers that iter is of type u16 because it is being used inside of my computation on line 4.
1 let mut numbers: [Option<u16>; 5];
2 for iter in 0..5 {
3 let number_to_add: u16 = { // `iter` moves to inner scope
4 ((iter * 5) + 2) / (4 * 16) // Infers `iter: u16`
5 };
6
7 numbers[iter] = Some(number_to_add); // Expects `iter: usize`
8 }
I am receiving the following error:
error[E0277]: the type `[std::option::Option<u16>]` cannot be indexed by `u16`
--> exercises/option/option1.rs:3:9
|
7 | numbers[iter] = Some(number_to_add);
| ^^^^^^^^^^^^^ slice indices are of type `usize` or ranges of `usize`
I tried casting iter as u16 inside the computation in line 4, but still having issues.
Where is my misconception?
Your assumption is correct. And your fix was ok too (it led to a different error, see below).
Your first problem was that for slice indexing, iter needs to be of type usize so either
numbers[iter as usize] = Some(number_to_add);
or
((iter as u16 * 5) + 2) / (4 * 16)
will lead to correct type inference through rustc.
Your second problem was that numbers was not initialized, so rustc correctly warns you when you try to modify numbers. Assigning a value, e.g.,
let mut numbers: [Option<u16>; 5] = [None; 5];
will let you compile your program.
Your reasoning is correct. Just to add, if you only want to initialize your array, you might also consider this way of doing it:
let arr_elem = |i: u16| Some(((i * 5) + 2) / (4 * 16));
let numbers : [Option<u16>; 5] = [
arr_elem(0),
arr_elem(1),
arr_elem(2),
arr_elem(3),
arr_elem(4),
];
This way, you do not need to have it mut (at the cost of writing a helper function to initialize a single element and stating the initializer elements, but that could be automated e.g. via a macro or some helper traits).
Aside from the existing answers, a somewhat higher level approach could also be cleaner (depending on taste)
let mut numbers = [None; 5];
for (i, n) in numbers.iter_mut().enumerate() {
let iter = i as u16;
let number_to_add: u16 =
((iter * 5) + 2) / (4 * 16);
*n = Some(number_to_add);
}
An other alternative would be a more lazy approach, but there's (afaik) no way to e.g. try_collect into an array, only try_from a slice to an array, so you'd need to collect() to a vec, then try_from to an array, which seems less than useful. Though you could always use an iterator to initialise you array:
let mut it = (0u16..5).map(|i| ((i * 5) + 2) / (4 * 16));
let numbers = [it.next(), it.next(), it.next(), it.next(), it.next()];
Also
// `iter` moves to inner scope
iter is Copy so it's just... copied. Kinda. And the block is not useful either, it only contains a simple expression.
I have this code in c++ and I used vectors but I got this error:
error: Vector subscript out of range error.
Can some help me in this issue.
int const TN = 4;
vector <uint32_t> totalBytesReceived(TN);
void ReceivePacket(string context, Ptr <const Packet> p)
{
totalBytesReceived[context.at(10)] += p->GetSize();
}
void CalculateThroughput()
{
double mbs[TN];
for (int f = 0; f<TN; f++)
{
// mbs = ((totalBytesReceived*8.0)/100000);
mbs[f] = ((totalBytesReceived[f] * 8.0) / 100000);
//totalBytesReceived =0;
rdTrace << Simulator::Now().GetSeconds() << "\t" << mbs[f] << "\n";
Simulator::Schedule(Seconds(0.1), &CalculateThroughput);
}
}
It seems like
totalBytesReceived[context.at(10)] += p->GetSize();
throws the exception because the char at position 10 of context is out of range. Since you use it to index the vector, it has to be in the range 0 to 3.
Looking at the content of context you posted:
"/NodeList/" 1 "/DeviceList/*/$ns3::WifiNetDevice/Mac/MacRx"
^ ^ ^
0 10 12
If you want to extract the 1 and use it as an index, you need to use:
char c = context.at(12); // Extract the char.
int index = c - '0'; // Convert the character '1' to the integer 1.
This is because of the ASCII standard which determines how characters are stored as numbers.
Probably the real issue is that you get the character '1' and use its ASCII value as index to the vector instead of the intended integer value 1.
This out of bounds access is then undefined behaviour, which in your case leads to an exception.
The following is not the cause, leaving it for reference:
The exception is probably coming from this expression:
context.at(10)
This is the only operation (*) involved that is actually performing bounds checking. The vector operator[] isn't doing that, neither does a C array check it's bounds.
So: Are you sure the string context is never shorter than 11 characters?
(*) Accessing a vector out of bounds is undefined behaviour, and throwing an exception is within the possible outcomes of that. Thanks to Beta Carotin and Benjamin Lindley for that.
This is the real thing:
Also note that a vector isn't resized like map when accessing an out of bounds index using operator[], so unless you can guarantee that the characters in the string are between 0 and 3 inclusive this will be your next issue.
And this means (size_t)0 and (size_t)3, not the characters '0' and '3'.
This question already has answers here:
What happens if I increment an array variable?
(5 answers)
Closed 7 years ago.
I am trying to learn pointers and string literals in C/C++.
As per my understanding, string literals are char arrays with a null \0 at the end. Also we can basically do all the pointer arithmetic operations on array like increment and decrement.
But when I am trying to run the following code:
#include <iostream>
using namespace std;
int main (){
char *c ="Hello";
char d[6];
while(*d++ = *c++);
cout<<c<<endl<<d;
}
I am getting the following error,
error: cannot increment value of type 'char [6]'
while(*d++ = *c++);
My assumption for this code was, that the values of string literal c will be copied to char array d.
Edit:
Now I am a bit confused about the difference between these 2 statements:
*(d++)
and
*(d+1)
assuming d is an array.
char d[6];
while(*d++ = *c++);
Should be Re-written to:
char d[6];
int idx = 0;
while(d[idx++] = *c++);
Because in char d[6];, d is an array (not to be confused with pointer) and you can not change the address of an array. On the other hand, type of c is char * so you can modify it.
c++; // OK
c = &d[0]; // OK
d++; // Not allowed
d = c; // Not allowed
About your added question:
Difference between: *(d++) and *(d+1)
Consider following example:
int index1 = 42, index2 = 42;
int j = index1++; // j = 42 and index1 = 43
int k = (index2 + 1); // k = 43 and index2 = 42 (unchanged)
Similarly when you write *(d++), you are trying to access (by dereferencing) the current location and then increment the pointer itself to next location. But when you write *(d + 1), you are accessing the next location and the pointer itself remains unchanged.
If the d pointer is constant or is an array first form (where d is changed) is not allowed but the second form (where the pointer itself remains unchanged) is allowed.
Array name can't be a modifiable lvalue
so
d++
can be written as
d = d+1;
So there is an error which should be fixed as
while(d[index++] = *c++);
I'm trying to write a code that would convert numbers into alphabets. For example 1 will be 'A', 2 will be 'B', 3 will be 'C' and so on. Im thinking of writing 26 if statements. I'm wondering if there's a better way to do this...
Thank you!
Use an array of letters.
char nth_letter(int n)
{
assert(n >= 1 && n <= 26)
return "abcdefghijklmnopqrstuvwxyz"[n-1];
}
If you can rely on the using an ASCII character set where they are consecutive then you can convert
char intToAlphabet( int i )
{
return static_cast<char>('A' - 1 + i);
}
If you can sometimes rely on this fact, e.g. you can set a compiler flag or similar for the particular target, you can also use this code for that specific build.
Otherwise use a static lookup table (as others have suggested).
Note that it is preferable to "assert" your range check if your numbered input comes from program variables that you know should never be out of range.
If the input comes from user-provided data where the users could potentially provide rogue data, you need a way to handle it that is not "undefined behaviour". Therefore you would have to check each value and either throw an exception (informing the user to correct their data) or use some character to indicate a bad input.
something like that
my_print(int x)
{
char symbol = (char)('A' + x - 1);
cout << symbol;
}
The simplest way would be using a table:
char
remap( int original )
{
static char const remap[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
return original >= 0 && original < sizeof(remap) - 1
? remap[ original ]
: '?'; // or throw, or ...
}
If you want to convert 0 to a, 1 to b, 2 to c ... 25 to z:
char covertedChar = (char)('a' + 2);
// Will print 'c'
cout << covertedChar;
Similary, to convert 0 to A, 1 to B, 2 to C ... 25 to Z:
char covertedChar = (char)('A' + 25);
// Will print 'Z'
cout << covertedChar;
So if you want to convert 1 to A, 2 to B, 3 to C ... 26 to Z, simply subtract 1 offset.
int toCovert = 26 // 'Z'
char covertedChar = (char)('A' + toCovert - 1);
// Will print 'Z'
cout << covertedChar;
How can i do a Bitwise OR on strings?
A:
10001
01010
------
11011
Why on strings?
The Bits can have length of 40-50.Maybe this could be problematic on int ?
Any Ideas ?
I would say std::bitset is more than enough for your situation, but for more flexibility you can use boost::dynamic_bitset. Here is an example on std::bitset:
const size_t N = 64;
string a_str = "10001", b_str = "01010";
bitset<N> a(a_str), b(b_str);
bitset<N> c = a | b;
cout << c;
You should take a look at the C++ std::bitset class, which does exactly what you want.
For each char:
char result = (a - '0') | (b - '0') + '0';
Where a and b are two chars with ascii character 0 or 1 in them.
Why not just use a vector of int values? Doesn't the bitset still use a byte per bit?
You can also use a vector of bool values, but this is also implementation specific.
Depending on whether you need storage efficiency or speed (or the utility of container methods that a couple of these approaches lack) you might profile to decide which approach to use.
This is similar to Andreas Brinck's answer, only it returns a full output string and can compare strings of different (arbitrary) lengths.
Example in C# (not near c++ compiler right now), but it should be simple to convert it to a language of your choice.
public static string BitwiseOr(string input1, string input2)
{
char[] inarr1 = (char[])input1.ToCharArray().Reverse().ToArray();
char[] inarr2 = (char[])input2.ToCharArray().Reverse().ToArray();
char[] outarr = new char[input1.Length > input2.Length ? input1.Length : input2.Length];
for (int i = 0; i < outarr.Length ; i++)
{
char c1 = i < input1.Length ? inarr1[i] : '0';
char c2 = i < input2.Length ? inarr2[i] : '0';
outarr[i] = (char)((c1 - '0') | (c2 - '0') + '0');
}
return new string((char[])outarr.Reverse().ToArray());
}
Of course this is only valid if you really need it to be in a string, if not you should (as suggested in other answers) use a vector or similar data type.