I apologize in advance if anything isn't clear enough.
While attempting to check if an index value exists of an array in D, I encountered an unexpected RangeError.
I'm attempting to make an array check function, and I wouldn't know how to check for a value in an array in D.
In C, I would use arr[index].
Execution Error:
core.exception.RangeError#test.d(6): Range violation
----------------
??:? _d_arrayboundsp [0x100f855d9]
??:? int checkArray(immutable(char)[][]) [0x100f6715e]
??:? _Dmain [0x100f7832e]
Code:
import std.stdio;
import std.stdc.stdlib;
import core.sys.posix.unistd;
int checkArray(string[] arr) {
if (!arr[1]) {
return 0;
} else {
return 1;
}
}
void main() {
string base = "test";
string[] cut = base.split(" ");
checkArray(cut);
}
I currently use a Mac, and used DMD to compile the source.
Should I try some other checker, other than arr[index]?
Firstly, never ever check if an index is within an array by dereferencing it.
bool check(int[] arr, size_t index)
{
return index < arr.length;
}
unittest {
assert(!check([], 0));
assert(!check([1], 1));
assert(check([1, 2], 1));
auto testArray = new int[1024];
//testArray[testArray.length] = 1; // this throws, so check should return false
assert(!check(testArray, testArray.length));
}
enjoy
Related
I want to pass a 2D array to a function, and the value of the array will not be modified in that function. So I am thinking about doing this way:
#include <Windows.h>
static INT8 TwoDimArrayConst(const INT8 ai_Array[2][2]);
int main(void)
{
INT8 ai_Array[2][2] = { { { 1 }, { 2 } }, { { 3 }, { 4 } } };
(void)TwoDimArrayConst(ai_Array); // Message 0432: [C] Function argument is not of compatible pointer type.
return 1;
}
static INT8 TwoDimArrayConst(const INT8 ai_Array[2][2])
{
INT8 test = 0;
for (INT8 i = 0; i < 2; i++)
{
for (INT8 k = 0; k < 2; k++)
{
if (ai_Array[i][k] > 0)
{
test = 1;
}
}
}
if (test == 0)
{
test = 2;
}
return test;
}
However, it gave me the QAC error when I enabled depth 5 QAC setting as the one I put is the code comment above:
// Message 0432: [C] Function argument is not of compatible pointer type.
If I remove the const in the function declaration and definition, so the function is like:
static INT8 TwoDimArrayConst(INT8 ai_Array[2][2]);
this error will be gone, but there will be another error saying:
> The object addressed by the pointer parameter 'ai_Array' is not
> modified and so the pointer could be of type 'pointer to const'.
So how to resolve this dilemma? I cannot define ai_Array to be const array in the main fuction since some other function may still want to modify the value.
Also, I am looking for the solution that still maintain the double brackets(no need to pass row size and column size as separate arguments) in the function, instead of treat it as a 1D array.
the following proposed code:
uses the C library functions rather than the windows functions, since I'm running on linux, not windows
performs the desired functionality
cleanly compiles
takes advantage of arrays, in C, being laid out consecutively in memory
takes advantage of "accessing an array name degrades to the address of the first byte of the array"
removes all the unneeded braces (which are doing nothing but cluttering the code)
documents why each header file is included
passes the size of the array as an parameter to the called function (should always either do this or include some kind of 'marker' in the contents of the array)
all the above allows treating the array as a 1 dimensional array
breaks out of the loop in the called function as soon as the terminating condition is encountered
BTW: the header file: windows.h is not portable
and now, the proposed code:
//#include <Windows.h>
#include <stdio.h> // printf()
#include <stdint.h> // int8_t
static int8_t TwoDimArrayConst( const int8_t *ai_Array, size_t size );
int main(void)
{
const int8_t ai_Array[2][2] = { { 1, 2 }, { 3, 4 } };
int8_t returnValue = TwoDimArrayConst(( int8_t* const )ai_Array, sizeof( ai_Array) / sizeof( int8_t ));
printf( "%d\n", returnValue );
return 1;
}
static int8_t TwoDimArrayConst( const int8_t *ai_Array, size_t size )
{
int8_t test = 2;
for ( size_t i = 0; i < size; i++)
{
if (ai_Array[i] > 0)
{
test = 1;
break;
}
}
return test;
}
A run of the proposed code results in:
1
in libconfig - is it possible to dymanically enumerate keys?
As an example, in this example config file from their repo - if someone invented more days in the hours section, could the code dynamically enumerate them and print them out?
Looking at the docs, I see lots of code to get a specific string, or list out an array, but I can't find an example where it enumerates the keys of a config section.
Edit
Received some downvotes, so thought I'd have another crack at being more specific.
I'd like to use libconfig to track some state in my application, read in the last known state when the app starts, and write it out again when it exits. My app stores things in a tree (of depth 2) - so this could be niceley represented as an associative array in a libconfig compatible file as below. The point is that the list of Ids (1234/4567) can change. I could track them in another array, but if I could just enumerate the 'keys' in the ids array below - that would be neater.
so
ids = {
"1234" = [1,2,3]
"4567" = [9,10,11,23]
}
e.g (psuedocode)
foreach $key(config_get_keys_under(&configroot)){
config_get_String($key)
}
I can't see anything obvious in the header file.
You can use config_setting_get_elem function to get n-th element of the group, array or list, and then (if it's group) use config_setting_name to get it's name. But AFAIK you can't use digits in key names. So consider following config structure:
ids = (
{
key = "1234";
value = [1, 2, 3];
},
{
key = "4567";
value = [9, 10, 11, 23];
}
);
Then you can easily enumerate through all members of the ids getting the values you want using the following code:
#include <stdio.h>
#include <libconfig.h>
int main(int argc, char **argv) {
struct config_t cfg;
char *file = "config.cfg";
config_init(&cfg);
/* Load the file */
printf("loading [%s]...\n", file);
if (!config_read_file(&cfg, file)) {
printf("failed\n");
return 1;
}
config_setting_t *setting, *member, *array;
setting = config_lookup(&cfg, "ids");
if (setting == NULL) {
printf("no ids\n");
return 2;
}
int n = 0, k, v;
char const *str;
while (1) {
member = config_setting_get_elem(setting, n);
if (member == NULL) {
break;
}
printf("element %d\n", n);
if (config_setting_lookup_string(member, "key", &str)) {
printf(" key = %s\n", str);
}
array = config_setting_get_member(member, "value");
k = 0;
if (array) {
printf(" values = [ ");
while (1) {
if (config_setting_get_elem(array, k) == NULL) {
break;
}
v = config_setting_get_int_elem(array, k);
printf("%s%d", k == 0 ? "" : ", ", v);
++k;
}
printf(" ]\n");
}
++n;
}
printf("done\n");
/* Free the configuration */
config_destroy(&cfg);
return 0;
}
I have written a type:
typedef struct
{
int Tape[TAPE_SIZE];
int *Head;
int Tape_Count;
int Loop_Start_Count;
} Tarpit;
I try to initialize this type with the following function:
void Tarpit_Initialize(Tarpit Tarpit)
{
Tarpit.Tape_Count = 0;
Tarpit.Loop_Start_Count = 0;
int Index;
for(Index = 0; Index < TAPE_SIZE; Index++)
{
Tarpit.Tape[Index] = INITIAL_SIZE;
}
}
However, it does not seem to work. If I run this:
Tarpit Foo;
Tarpit_Initialize(Foo);
printf("Tarpit Initialization Test: \n");
int index;
for(index = 0; index < TAPE_SIZE ; index++)
{
if(Foo.Tape[index] == INITIAL_SIZE)
{
printf("%d: %d \n", index, Foo.Tape[index]);
}
else
{
printf("%d: %d !ERROR \n", index, Foo.Tape[index]);
}
}
I get several non-zero values (I have set #define TAPE_SIZE 10000 and #define INITIAL_SIZE 0)
Moreover, if I run the test without running Tarpit_Initialize(Foo), I get exactly the same results. The initializer does not seem to work. Why/how could I implement it in an other way? I would like to set every element of Foo.Tape to zero.
Problem solved!
You are passing Tarpit by value:
void Tape_Initialize(Tarpit Tarpit)
That means it is only a copy of Tarpit. You have to pass a pointer to it to be able to modify it.
void Tape_Initialize(Tarpit* Tarpit)
and pass it as pointer (note the name of the function called!):
Tape_Initialize(&Foo);
and the use the -> operator to modify it. For instance:
Tarpit->Tape_Count = 0;
Moreover, as "Elias Van Ootegem" pointed out, you should not use sizeof(Tarpit.Tape) to get the size of the array but TAPE_LENGTH that you defined. Because sizeof() will give you a size in bytes not in elements.
Have you checked the function u are calling ??
Its "Tarpit_Initialize(Foo);"
But the Function u are using it to initialize "void Tape_Initialize(Tarpit Tarpit)".
I think even what u have implemented should work fine .
I have the following C code:
VALUE find_index(VALUE arr, VALUE num_elements, VALUE element){
....
}
....
VALUE array_distance(VALUE arr1, VALUE arr2){
long arr1_len = RARRAY_LEN(arr1);
VALUE *c_arr2 = RARRAY_PTR(arr2);
long i;
for(i = 0; i < arr2_len; i++){
long arr1_index = find_index(arr1, arr1_len, c_arr2[i]);
....
}
}
When compiling this, I get the following error:
In function ‘VALUE array_distance(VALUE, VALUE, VALUE)’:
error: too few arguments to function ‘VALUE find_index(VALUE, VALUE, VALUE, VALUE)’
Can someone help with what is wrong here?
If you want to use your C functions in other C code inside, you need to use builder.c_raw instead of builder.c, because RubyInline actually tries to make your life easier by changing your code so you can write simple functions quickly. This is however misleading and keeps you from calling your C functions from inside other C functions, because the method signature is altered. This should get you started:
class Test
inline :C do |builder|
builder.c_raw <<-'EOC', :arity => 3
static VALUE
find_index(int argc, VALUE *argv, VALUE self) {
VALUE arr = argv[0];
VALUE num_elements = argv[1];
VALUE element = argv[2];
// actual code...
}
EOC
builder.c_raw <<-'EOC', :arity => 2
static VALUE
array_distance(int argc, VALUE *argv, VALUE self) {
long arr1_len = RARRAY_LEN(argv[0]);
VALUE *c_arr2 = RARRAY_PTR(argv[1]);
long i;
for(i = 0; i < arr2_len; i++){
VALUE[] find_index_argv = {arr1, arr1_len, c_arr2[i]};
long arr1_index = find_index(argc, find_indev_argv, self);
// more code...
}
// must have a return value!
return Qnil;
}
EOC
end
end
Also why does this give me an error because I used bool?
I need to use this sequential search algorithm, but I am not really sure how. I need to use it with an array. Can someone point me in the correct direction or something on how to use this.
bool seqSearch (int list[], int last, int target, int* locn){
int looker;
looker = 0;
while(looker < last && target != list[looker]){
looker++;
}
*locn = looker;
return(target == list[looker]);
}
Looks like you'd use it like this...
// I assume you've set an int list[], an int listlen and an int intToFind
int where;
bool found = seqSearch(list, listlen - 1, intToFind, &where);
if (found)
{
// list[where] is the entry that was found; do something with it
}
It's pretty clear
list[] is the list you are searching
last is the last index in the list
target is what you are searching in list
locn will contain the index at which target was found
the return value is a boolean indicating if the target was found
for your question how to pass locn, do something like
int locn; /* the locn where the index of target will be stored if found */
bool target_found = seqSearch(blah blah blah, &locn);
The problem with your code is if you search for an element not present in the array, looker will be equal to last and you try to access an array element at location last which is invalid.
Instead you can do:
bool seqSearch (int list[], int last, int target, int* locn) {
int looker;
for(looker=0;looker<last;looker++) {
// target found.
if(list[looker] == target) {
*locn = looker; // copy location.
return true; // return true.
}
}
// target not found.
*locn = -1; // copy an invalid location.
return false; // return false.
}
You call the function as follows:
int list[] = {5,4,3,2,1}; // the array to search in.
int size = sizeof(list)/sizeof(list[0]); // number of elements in the array.
int target = 3; // the key to search for.
int locn; // to hold the location of the key found..and -1 if not found.
if( seqSearch(list,size,target,&locn) ) {
// target found in list at location locn.
} else {
// target not found in list.
}
There are a few issues.
I would change the name of last to size.
If you don't find the value, you will dereference an invalid memory location.
EDIT: I guess last is the length - 1. That's an unusual signature. So the call is something like:
int list[CONSTANT];
...
int foundIndex;
bool found = seqSearch(list, sizeof(list)/sizeof(int), target, &foundIndex);
There are many ways to enable bool. One is to use stdbool.h with C99.