C to Perl conversion of *ptr++ - c

I have a pointer to an array and either need to change the code considerably to make this work, or just figure out what the equivilent of the statement below is...
ptr = array;
*ptr++ = value;
So far I have most of it
$ptr = \#array;
$$ptr = $value;
but this doesn't increment the pointer. What do I do?

There are no pointers in Perl. What you have is:
my $ary_ref = \#array;
$ary_ref is now a reference to #array. You cannot dereference $ary_ref to get a scalar.
You can, however, iterate through the elements of #array in a variety of ways. For example, if you want, you can do:
#!/usr/bin/env perl
use strict; use warnings;
my #array;
my $ptr = sub {
my ($i, $ref, $val, $size) = (0, #_);
sub { $i < $size ? $ref->[$i ++ ] = $val : () }
}->(\#array, deadbeaf => 10);
1 while defined $ptr->();
use YAML;
print Dump \#array;
By the way, there is no reason you can't write
p[i] = value;
i++;
in C. In Perl, it might become:
$array[$_] = $value for 0 .. $#array;
or,
#array = ($value) x #array;
or,
$_ = value for #array;
etc. You should explain what the overall goal is rather than asking about a specific statement in C.

The C code modifies the first element of array and will likely change at least some part of the rest of the array.
#include <stdio.h>
int main(void)
{
int array[] = { 0, 0, 0, 0, 0 };
int value = 42;
int *ptr;
int i;
ptr = array;
*ptr++ = value;
for (i = 0; i < sizeof(array) / sizeof(array[0]); i++)
printf("%d ", array[i]);
puts("\n");
return 0;
}
Output:
42 0 0 0 0
Perl has references rather than pointers. References cannot be null, but there’s no reference arithmetic.
Modifying the first element of an array in Perl looks like
$ perl -wle '#a=(0)x5; $a[0] = 42; print "#a"'
42 0 0 0 0
or to be excessively literal
$ perl -wle '#a=(0)x5; $ptr = \$a[0]; $$ptr = 42; print "#a"'
42 0 0 0 0
Your question gives a single bookkeeping detail of the C code. What’s the broader context? What’s the C code doing?
In general, don’t write C in Perl. Considered broadly, C code tends to process arrays one item at a time, but Perl modifies the entire conceptual chunk, e.g., with a regex for strings or map or grep to transform entire arrays.

Related

How to fetch values of sub array present in array

I have created one array and pushing another array in each iteration of loop into it. Once it will be done I wanted to fetch the values of each sub array as well as array.
Code I am using :
my $i;
my #carrierValuesAll="";
while (my #row = $sth->fetchrow_array()) {
my #carrierValues=join(',', #row). "\n";
push(#carrierValuesAll, #carrierValues);
}
$len = #carrierValuesAll;
for ($i = 0; $i < $len; $i = $i + 1) {
print ("\#carrierValuesAll[$i] = $carrierValuesAll[$i]\n");
print("\n");
}
The output I am getting is :
#carrierValuesAll[1] = 1,1,https://au-sbc.trustidinc.com/tid,sbcLabStub,sbcLab,,SKY,0,2019-11-07 20:10:43,2021-07-02 04:39:43,TrustID Lab Oracle,Y,Y,Y,ivr.localdomain,Y,trustid
#carrierValuesAll[2] = 2,1,https://au-sbc.trustidinc.com/tid,sbcLab,sbcLab,,SKY,2,2019-11-07 20:10:43,2020-12-14 06:24:17,TrustID Lab Oracle,Y,Y,Y,ivr.localdomain,Y,admin
What I have tried :
$len = #carrierValuesAll;
for ($i = 0; $i < $len; $i = $i + 1) {
print ("\#carrierValuesAll[$i] = $carrierValuesAll[$i]\n");
print("\n");
for (my $j=0;$j<$carrierValuesAll[$i];$j++) {
print("\#carrierValuesAll[$j] = $carrierValuesAll[$j]\n");
print("\n");
}
}
added one more nested loop into it, but it wont helped.
This output is what coming from database & I am trying to store it in array.
You only have one array here - well you have a second array variable, but you only ever store a single, scalar value in it.
Let's look at your code:
my $i;
my #carrierValuesAll="";
Declaring $i so far away from where it is used is a bit of a code smell. It'll work fine, of course, but Perl gives you the flexibility to declare variables where you use them - so use it.
And #carrierValuesAll="" isn't doing what you think it's doing. I suspect you think it's declaring an empty array. But actually it creates an array containing a single element which is an empty string.
while (my #row = $sth->fetchrow_array()) {
my #carrierValues=join(',', #row). "\n";
push(#carrierValuesAll, #carrierValues);
}
You now declare a new array, #carrierValues, but you give it a value which is returned from join(). The whole point of join() is to take a list of values (your data in #row) and join it together into a single string. You then push that single string onto the end of #carrierValuesAll.
There is no point in storing the result from join() in an array. The result from join() is only ever a single, scalar value.
So after this loop has finished running, you have an array, #carrierValuesAll which contains one of these single strings for each of the rows in your database table. There are no "subarrays" here. Just an array of strings.
You then confirm that by printing the contents of #carrierValuesAll.
$len = #carrierValuesAll;
for ($i = 0; $i < $len; $i = $i + 1) {
print ("\#carrierValuesAll[$i] = $carrierValuesAll[$i]\n");
print("\n");
}
And that prints exactly what I would expect. You get the data that you read from the database separated by commas.
If you don't want a single string, then don't use join() to make one. Instead, take a copy of #row and store a reference to that in your array:
while (my #row = $sth->fetchrow_array()) {
push(#carrierValuesAll, [ #row ]);
}
I'm not sure what you want to do with your array of arrays, but here's how you could print it out:
$len = #carrierValuesAll;
for (my $i = 0; $i < $len; $i = $i + 1) {
print ("\#carrierValuesAll[$i] = #{$carrierValuesAll[$i]}\n");
print("\n");
}
Note that I've used #{$carrierValuesAll[$i]} to dereference the array reference stored at $carrierValuesAll[$i] and turn it back into an array which I can then print.
Note also that I've moved the declaration of $i into the for loop where it makes more sense.
But most Perl programmers wouldn't use this "C-style" for loop as it looks horrible and is harder to understand. I would write this code as:
for my $i (0 .. $#carrierValuesAll) {
...
}
Instead of calculating the length of the array and then remembering to stop one iteration before reaching that, I've used the special variable $#ARRAY which gives me the index of the last index in the array.

how to get the number of elements in a 2D array in Perl

I am working with a 2D array in Perl, and have come across a stumbling block, that I am hoping someone can help me with.
I am reading a file that has x number of lines and y number of columns, this I am placing into a 2D array,
for testing purposes I am trying to print out the contents of the first element(line) in the array using a for loop:
for( $m = 0; $m <= $#fields; $m++)
{
printf "Field [0][$m] = $fields[0][$m]\n";
}
The problem I am running into is that this loops for the entire size of array rather then the length of the 2nd element.
Any help will be appreciated.
Use the $#{} dereference to get the last index of an array reference:
for (my $m = 0; $m <= $#{ $fields[0] }; $m++)

How can you initialize an entire array at once in GML?

I want to initialize an entire array at once but I can't find any examles of this being done anywhere.
I want to do something like this:
int a [][] = {{0,1,0},
{0,1,1},
{2,1,0}};
Unfortunately GML is not like many other languages in the sense that GML does not have single line array initialization. You can easily write a script to accomplish this, but the GML docs use this method to initialize arrays. The example they gave initializes a 10 record array (0-9) with zeros.
var i;
i = 9;
repeat(10)
{
array[i] = 0;
i -= 1;
}
If you want different values for every record then you have to manually type every position. This is the example the docs gave.
count = 3;
array[count] = "you?"
count -= 1;
array[count] = "are "
count -= 1;
array[count] = "How "
count -= 1;
array[count] = "Hello!"
count -= 1;
In regards to a script: Here is a simple one for 1D arrays. Used as var myArray = array(record 1, record 2, 3, 4, ...)
///array(*args);
var arr;
for (var i=0;i<argument_count;i+=1)
{
arr[i] = argument[i];
}
return arr;
If you are using a current version of GameMaker, there's array literal syntax in form of [...items] (documentation). So you can do
a = [[0,1,0],
[0,1,1],
[2,1,1]];
and that'll work fine.
The only thing to note that this'll produce an array of arrays (which is how arrays work in most languages) rather than GML-specific legacy 2d array, so you'd need to use a pair of [index] accessors rather than [index1, index2].

How to get around the scope of the foreach loop in Perl

So I'm working through a bit of code that my compiler really doesn't like. There are two arrays, that have an identical number of indexes. #array is populated with 0's, #otherarray is populated sequentially. In this foreach loop, it skips over the first value because it is filled outside the loop. Count is declared as 1 outside the loop as well.
foreach (#array) {
if ($count == 1) {
} elsif($_ == 0 && #otherarray[$count-1] != undef) {
$_ = $count;
splice(#otherarray, #otherarray[$count - 1], 1);
} else {
$_ = $otherarray[ rand #otherarray ];
}
$count++
}
It insists that I have use of uninitialized value in numeric ne(!=) on this line, and every line in which other array is inside an else/if/elsif statement:
elsif($_ == 0 && #otherarray[$count-1] != undef)
How do I work around this? I'm sure it's obvious but I'm really new to Perl, so I'm probably setting something up wrong in the first place? I have already declared my #otherarray.
It is the undef in the comparison which is uninitialized. Use defined instead of comparing to undef:
elsif($_ == 0 && defined($otherarray[$count-1]))

How do I multiply more than two matrices in perl?

I am sending in an array of references and here is my subroutine:
sub multiply
{
my #product;
my $ref1 = $_[0];
my $ref2 = $_[1];
my #array1 = #$ref1;
my #array2 = #$ref2;
}
my ($rowsA,$columnsA) = &dimensions(#$ref1);
my ($rowsB,$columnsB) = &dimensions(#$ref2);
for $i (0..$rowsA-1){
for $j (0..$columnsB-1){
for $k (0..$columnsA-1){
$product[$i][$j] += $array1[$i][$k] * $array2[$k][$j];
}
}
}
This subroutine works for two parameters, but how do I multiply the matrices when more than two parameters are sent?
You want to use the #_ array directly. You won't be able to assign your references directly as you have in your example b/c as you have found, you don't know the number of items being passed. The good thing is, you don't need too. All arguments are passed to Perl sub-routines via the special #_ array. When you see my $x = shift; this array is where the data is being shifted from into your local variables. Here, since you can't know ahead of time how many vars to create, you can use the array directly. Typical array functions apply. (i.e. to get size you can use scalar(#_))
The following example displays the type of sub-routine you would write using regular scalars. It would be the same for references, you would just need to dereference them prior to their use.
#!/usr/bin/perl
my $result = multiply(2,4,5);
print "Result 1: $result\n";
$result = multiply(2,2);
print "Result 2: $result\n";
$result = multiply(2,2,3,5,6);
print "Result 3: $result\n";
sub multiply
{
my $ans = 1;
foreach my $x (#_) { $ans *= $x; }
return $ans;
}
To be combined with RC's answer, which explains what #_ is and how to use it, you can also recurse:
sub multiply {
return $_[0] * $_[1] if #_ <= 2;
return shift( #_ ) * multiply( #_ );
}
It won't be as fast as his answer, but for more complex tasks, can be easier to implement.

Resources