trying to make my "fillvalues" function work...

  • Thread starter =?ISO-8859-1?Q?Martin_J=F8rgensen?=
  • Start date
?

=?ISO-8859-1?Q?Martin_J=F8rgensen?=

Hi,

I'm trying to move a matlab program into c language. For those who knows
matlab, this is the line I want to program in c:

hx(1:nx,1:ny) = 0; % nx=10, ny=10

It works on a 2-dimensional array (size is 10*10), setting all the
values inside the 10*10 matrix to zero. My C-function looks like this:


void fillinnumbers(int fillvalue, int startx, int stopx, int starty, int
stopy, int array[][])
{
for(i=startx; i<=stopx; i++)
{
for(j=starty; j<=stopy; j++)
{
array[j] = fillvalue;
}
}
}


So, taken the above example: fillvalue = 0, startx = 1, stopx = nx = 10,
starty = 1, stopy = ny = 10, array[][] is the pointer... Now, the
problem is that I'm a C newbie so I there's something wrong with the
array[][] thing, I think...

In my C-program I tried:

fillinnumbers(3, 1, nx, 1, ny, array);

I defined array as: array[nx+1][ny+1]

But using MSVS 2005, I get the following error: "error C2087: 'array' :
missing subscript" - the error points to the line containing the
function declaration: "void fillinnumbers(int fillvalue,.... etc"

And a lot of warnings: "warning C4048: different array subscripts : 'int
(*)[1]' and 'int [11][11]" in each line where I try to call my function
such as in the line containing: "fillinnumbers(3, 1, nx, 1, ny, array);"

I'm not so experienced with C programming, so any help will be greatly
appreciated...


Best regards / Med venlig hilsen
Martin Jørgensen
 
W

Walter Roberson

int array[][]

You cannot declare an array like that in C.

There are different kinds of multi-dimensional arrays in C90.

One of them is a block of consequative memory addresses. In order
for C to be able to find the proper location in that block, it
needs to know what maximum size was for all of the dimensions except
the last, as it needs to do the equivilent of
(i-1)*maxfirstdim + (j-1) in order to find the offset from the
beginning of the block of memory. But C doesn't record that dimensional
information as a property of pointers that get passed around, so
when you pass one of these kinds of arrays into another routine,
that other routine has to have a declaration of the array size.

In C90, it is not possible to pass in the size of a multidimensional
array and have a declaration that varies with the passed size.

In C99, the capability to do that was added. But in the context
of your routine, you would need an additional parameter to indicate
the maximum dimension, as your stopx variable is used to indicate
the maximum subscript of the the block that should be filled
rather than the maximum subscript that is possible for the array.


The other major kind of multi-dimensional array is to have each
level of the array -except- the last be a vector (one-dimensional
array) of pointers to objects of the next lower dimensionality,
until finally the second-last dimension is a vector of pointers
to values. There is more than one way to declare such an object
within a parameter list; some people would use, e.g.,
int **array
Using this array in the code would still look exactly the same,
array[j]
but it would mean something completely different than in the first
kind of array: it would mean to access the i'th location from
the beginning of the location named array, and that that location
should be used as a pointer to a block of memory, which you
would then take the j'th element of. When you use this kind of
multi-dimensional array, it is not necessary for functions to
know ahead of time what the maximum sizes are for each dimension --
but it also means that the actual memory used to store the array
values is -likely- not a plain block of storage (since pointers
might point all over the place in memory.)
 
?

=?ISO-8859-1?Q?Martin_J=F8rgensen?=

Walter said:
to values. There is more than one way to declare such an object
within a parameter list; some people would use, e.g.,
int **array
Using this array in the code would still look exactly the same,
array[j]
but it would mean something completely different than in the first
kind of array: it would mean to access the i'th location from
the beginning of the location named array, and that that location
should be used as a pointer to a block of memory, which you
would then take the j'th element of. When you use this kind of


Ok... Do I have to use malloc or something? Because I'm not really into
that function yet...
multi-dimensional array, it is not necessary for functions to
know ahead of time what the maximum sizes are for each dimension --
but it also means that the actual memory used to store the array
values is -likely- not a plain block of storage (since pointers
might point all over the place in memory.)

Ok... Perhaps somebody could post a working example, that I could learn
from? I understand what you write, but I'm just not sure if I know how
to program it...

Okay, I assume in the beginning of the program, I would declare:

array** int

Now, I "stole/borrowed" something from another code - perhaps I can use
this (I don't even know if this is necessary?):

doublearray = (double**) malloc((size_t) 2*(sizeof(double*)));

for(i=0;i<2;i++)
{
doublearray = (double*) malloc((size_t) 1700*(sizeof(double)));
}

Now since I will also be using my "fillvalues" function on integers I
assume I just replace the word "double" in the above with "int". I know
that the above works on a 1700*2 array, so if I should modify it to
10*10 then I guess I just change the number 2->10 and 1700->10?


Best regards / Med venlig hilsen
Martin Jørgensen
 
R

Robin Haigh

Martin Jørgensen said:
Walter said:
to values. There is more than one way to declare such an object
within a parameter list; some people would use, e.g.,
int **array
Using this array in the code would still look exactly the same,
array[j]
but it would mean something completely different than in the first
kind of array: it would mean to access the i'th location from
the beginning of the location named array, and that that location
should be used as a pointer to a block of memory, which you
would then take the j'th element of. When you use this kind of


Ok... Do I have to use malloc or something? Because I'm not really into
that function yet...
multi-dimensional array, it is not necessary for functions to
know ahead of time what the maximum sizes are for each dimension --
but it also means that the actual memory used to store the array
values is -likely- not a plain block of storage (since pointers
might point all over the place in memory.)

Ok... Perhaps somebody could post a working example, that I could learn
from? I understand what you write, but I'm just not sure if I know how
to program it...

Okay, I assume in the beginning of the program, I would declare:

array** int

Now, I "stole/borrowed" something from another code - perhaps I can use
this (I don't even know if this is necessary?):

doublearray = (double**) malloc((size_t) 2*(sizeof(double*)));

for(i=0;i<2;i++)
{
doublearray = (double*) malloc((size_t) 1700*(sizeof(double)));
}

Now since I will also be using my "fillvalues" function on integers I
assume I just replace the word "double" in the above with "int". I know
that the above works on a 1700*2 array, so if I should modify it to
10*10 then I guess I just change the number 2->10 and 1700->10?



In relation to your original code, replace 2 by (nx+1) and 1700 by (ny+1).
You've got irrelevant complications here because of the change of subscript
base from 1 to 0. You can drop the casts.


That scheme is most useful when the rows are strings of varying length,
since you can set the length of each row separately. This is a simpler C90
version for uniform rows:

/* prototype */
void fillinnumbers(int, int, int, int, int, int **);

/* definition */
void fillinnumbers(int fillvalue, int startx, int stopx, int starty, int
stopy, int **array)
{
for(i=startx; i<=stopx; i++)
for(j=starty; j<=stopy; j++)
array[j] = fillvalue;
}

/* caller */
int **array = malloc((nx+1)*sizeof(int*));
array[0] = malloc((nx+1)*(ny+1)*sizeof(int));
for (i = 1; i < nx+1 ;i++)
array = array[i-1] + ny+1; /* save start address of each row */
fillinnumbers(3, 1, nx, 1, ny, array);
free(array[0]);
free(array);



Or, you can just do the subscript arithmetic on the fly as required, instead
of storing the row addresses. Think of the "rows" as being segments of a
long one-dimensional array. Note that you have to pass the width around to
wherever subscript arithmetic is needed



/* prototype */
void fillinnumbers(int, int, int, int, int, int, int *);

/* definition */
void fillinnumbers(int fillvalue, int startx, int stopx, int starty, int
stopy, int ncols, int *a)
{
for(i=startx; i<=stopx; i++)
{
int *array_i = a + i*ncols;
for(j=starty; j<=stopy; j++)
array_i[j] = fillvalue;
}
}

/* caller */
int *p = malloc((nx+1)*(ny+1)*sizeof(int));
fillinnumbers(3, 1, nx, 1, ny, ny+1, p);
free(p);



But you don't need to do any of that. Your compiler has the variable-length
array support from C99. This must be everybody's favourite improvement, but
the advantage will never be realised if everybody insists on making their
code back-portable to C90 for ever.

In C99 all you need is an extra parameter and a bit of clever syntax:

/* prototype */
void fillinnumbers(int, int, int, int, int, int, int array[][*]);

/* definition */
void fillinnumbers(int fillvalue, int startx, int stopx, int starty, int
stopy, int ncols, int array[][ncols])
{
for(i=startx; i<=stopx; i++)
for(j=starty; j<=stopy; j++)
array[j] = fillvalue;
}

/* caller */
int array[nx+1][ny+1];
fillinnumbers(3, 1, nx, 1, ny, ny+1, array);
 
?

=?ISO-8859-1?Q?Martin_J=F8rgensen?=

Robin said:
-snip-

That scheme is most useful when the rows are strings of varying length,
since you can set the length of each row separately. This is a simpler C90
version for uniform rows:

/* prototype */
void fillinnumbers(int, int, int, int, int, int **);

/* definition */
void fillinnumbers(int fillvalue, int startx, int stopx, int starty, int
stopy, int **array)
{
for(i=startx; i<=stopx; i++)
for(j=starty; j<=stopy; j++)
array[j] = fillvalue;
}

/* caller */
int **array = malloc((nx+1)*sizeof(int*));
array[0] = malloc((nx+1)*(ny+1)*sizeof(int));
for (i = 1; i < nx+1 ;i++)
array = array[i-1] + ny+1; /* save start address of each row */
fillinnumbers(3, 1, nx, 1, ny, array);
free(array[0]);
free(array);


Damn... Having spent 4 hours or so on this I think I made a program
using the above that works... But I would like to debug it using MSVS
2005 and found that array points to 0x003a4d58. I then click the + sign
and it shows me a value of 0x003a4db0. There's yet another +-sign so I
click on it and find the value -842150451. I don't know quite how to
interpret this since I've never worked with 2D-arrays like this so
please bear over with me and let me know how to understand these memory
numbers...

Since this is a 2D-array what's the easist way of seeing the memory
content at location array[2][2] for instance? Might be there's some
hand-calculation involved? I guess I'll have to do something like
0x003a4d58 + 2 rows + 2 columns and watch that memory address, right?
Or, you can just do the subscript arithmetic on the fly as required, instead
of storing the row addresses. Think of the "rows" as being segments of a
long one-dimensional array. Note that you have to pass the width around to
wherever subscript arithmetic is needed



/* prototype */
void fillinnumbers(int, int, int, int, int, int, int *);

/* definition */
void fillinnumbers(int fillvalue, int startx, int stopx, int starty, int
stopy, int ncols, int *a)
{
for(i=startx; i<=stopx; i++)
{
int *array_i = a + i*ncols;
for(j=starty; j<=stopy; j++)
array_i[j] = fillvalue;
}
}

/* caller */
int *p = malloc((nx+1)*(ny+1)*sizeof(int));
fillinnumbers(3, 1, nx, 1, ny, ny+1, p);
free(p);

That looks like the most complicated/confusing method to me, but I also
read that it's possible to transfer a 2D-array to a 1D-array...
But you don't need to do any of that. Your compiler has the variable-length
array support from C99. This must be everybody's favourite improvement, but
the advantage will never be realised if everybody insists on making their
code back-portable to C90 for ever.

In C99 all you need is an extra parameter and a bit of clever syntax:

/* prototype */
void fillinnumbers(int, int, int, int, int, int, int array[][*]);

/* definition */
void fillinnumbers(int fillvalue, int startx, int stopx, int starty, int
stopy, int ncols, int array[][ncols])
{
for(i=startx; i<=stopx; i++)
for(j=starty; j<=stopy; j++)
array[j] = fillvalue;
}

/* caller */
int array[nx+1][ny+1];
fillinnumbers(3, 1, nx, 1, ny, ny+1, array);


This was actually the first thing I tried... I wanted to try this last
thing first, because it seemed very easy. But I got these for the line
"void fillinnumbers(int fillvalue, int startx, int"...

error C2057: expected constant expression
error C2466: cannot allocate an array of constant size 0
error C2087: 'array' : missing subscript

Therefore I tried your first solution and it seems to work (I inserted
prinft(" -> %i ", array[j]); in a new function very similary to the
fillinnumbers function...


Best regards / Med venlig hilsen
Martin Jørgensen
 
?

=?ISO-8859-1?Q?Martin_J=F8rgensen?=

-snip-

Damn.... Am i just blind or something... Why the hell is MS VS 2005
complaining about this code:

---------

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
printf("ADI Method is used.\n");

int **array = malloc((nx+1)*sizeof(int*));

return 0; /* ANSI-C requires main to return integer */

} /* End of main program */

-----

error C2143: syntax error : missing ';' before 'type' in the line: "int
**array = malloc((nx+1)*sizeof(int*));" - but there *IS* a semicolon... ???


Best regards / Med venlig hilsen
Martin Jørgensen
 
R

Richard Heathfield

Martin Jørgensen said:
-snip-

Damn.... Am i just blind or something... Why the hell is MS VS 2005
complaining about this code:

---------

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
printf("ADI Method is used.\n");

That's code...
int **array = malloc((nx+1)*sizeof(int*));

....and that's a declaration, which follows the code.

Solution: move (or remove) the printf.
 
R

Richard G. Riley

Martin Jørgensen said:


That's code...


...and that's a declaration, which follows the code.

Solution: move (or remove) the printf.

Isn't that very compiler/C version specific?

I've been swapping between languages so much recently that I totally
forgot about limitations on where and when you can declare
variables. Whats the C standard these days?
 
F

Flash Gordon

Martin Jørgensen wrote:

Damn.... Am i just blind or something... Why the hell is MS VS 2005
complaining about this code:

---------

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
printf("ADI Method is used.\n");

int **array = malloc((nx+1)*sizeof(int*));

return 0; /* ANSI-C requires main to return integer */

} /* End of main program */

Perhaps it is complaining because in C89 (the only C standard MS VS any
version supports) you can't mix declarations and statements.

Of course, the error message it is giving you is completely unhelpful.
 
F

Flash Gordon

Richard G. Riley wrote:

<snip intermixing declarations and statements and an error reported by
MS VS 2005>
Isn't that very compiler/C version specific?

I've been swapping between languages so much recently that I totally
forgot about limitations on where and when you can declare
variables. Whats the C standard these days?

It's dependant on the version of the standard implemented by the
compiler (or whether it allows it as an extension). The ability to
intermix statements and declarations was added in C99 but MS has decided
not to implement C99.
 
?

=?ISO-8859-1?Q?Martin_J=F8rgensen?=

Flash said:
Martin Jørgensen wrote:




Perhaps it is complaining because in C89 (the only C standard MS VS any
version supports) you can't mix declarations and statements.

Of course, the error message it is giving you is completely unhelpful.

OMFG! What a fucking psychopathic error message... I spend hours looking
for a missing semi-colon and couldn't find it... But now it seems to
work, thanks...

BTW: I'm wondering... Each time I use malloc(), shouldn't I also do a
check like this:

if (ptd == NULL)
{
puts("Memory allocation failure. Bye\n");
exit(EXIT_FAILURE);
}

?

Because I didn't use it anywhere and now I got about 8-10 malloc() in my
new program (which partly has been converted from Matlab)...


Best regards / Med venlig hilsen
Martin Jørgensen
 
M

MrG{DRGN}

Martin Jørgensen said:
-snip-

Damn.... Am i just blind or something... Why the hell is MS VS 2005
complaining about this code:

---------

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
printf("ADI Method is used.\n");

int **array = malloc((nx+1)*sizeof(int*));

return 0; /* ANSI-C requires main to return integer */

} /* End of main program */

-----

error C2143: syntax error : missing ';' before 'type' in the line: "int
**array = malloc((nx+1)*sizeof(int*));" - but there *IS* a semicolon...
???

Ok the first thing I can see is that you need to declare int **array =
malloc((nx+1)*sizeof(int*));
before the printf line like so;

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
int **array = malloc((nx+1)*sizeof(int*));

printf("ADI Method is used.\n");

return 0; /* ANSI-C requires main to return integer */
} /* End of main program */

After that you'll get an a different error which I think you should be able
to fix on your own. A clue... What is the value of nx?

Good Luck
 
M

Michael Mair

Martin Jørgensen schrieb:
BTW: I'm wondering... Each time I use malloc(), shouldn't I also do a
check like this:

I assume ptd contains the result of a malloc() call.
if (ptd == NULL)
{
puts("Memory allocation failure. Bye\n");

Usually, it is a good idea to put error messages to stderr, i.e.
fputs("Your error message here\n", stderr);
as this gives the user the choice whether to suppress or redirect
output and/or errors (i.e. stdout and/or stderr).
exit(EXIT_FAILURE);

This is the most drastic of all possible error treatments.
It may be better to
- try to salvage the situation by trying to allocate less memory
- terminate orderly, if that does not work/is not possible; this
includes writing out the output as far as it is ready, freeing
all resources used by your program.
- ... (whatever you can come up with, maybe even switching to a
less memory but more time consuming method).
}

?

Because I didn't use it anywhere and now I got about 8-10 malloc() in my
new program (which partly has been converted from Matlab)...

By all means: Yes!
Always check the return value of malloc() and introduce reasonable
error handling. Check this error handling by demanding absurdly
much memory or changing if (ptd == NULL) to if (0 && ptd == NULL).
Writing out an error message and aborting is often what you see
in newsgroups but it is most of the time insufficient in real life.


Cheers
Michael
 
J

Jordan Abel

Martin Jørgensen schrieb:


I assume ptd contains the result of a malloc() call.

Usually, it is a good idea to put error messages to stderr, i.e.
fputs("Your error message here\n", stderr);
as this gives the user the choice whether to suppress or redirect
output and/or errors (i.e. stdout and/or stderr).


This is the most drastic of all possible error treatments.
It may be better to
- try to salvage the situation by trying to allocate less memory
- terminate orderly, if that does not work/is not possible; this
includes writing out the output as far as it is ready, freeing
all resources used by your program.

It can be argued that good program design includes causing exit() result
in an orderly termination - this can be accomplished, to some extent, by
setting up atexit() handlers.
- ... (whatever you can come up with, maybe even switching to a
less memory but more time consuming method).

Or simply failing your own function and letting the caller deal with it.
this is what fopen() does, for example, on many systems, if it fails to
allocate memory for a FILE structure.
 
R

Robin Haigh

Martin Jørgensen said:
Robin said:
-snip-

That scheme is most useful when the rows are strings of varying length,
since you can set the length of each row separately. This is a simpler C90
version for uniform rows:

/* prototype */
void fillinnumbers(int, int, int, int, int, int **);

/* definition */
void fillinnumbers(int fillvalue, int startx, int stopx, int starty, int
stopy, int **array)
{
for(i=startx; i<=stopx; i++)
for(j=starty; j<=stopy; j++)
array[j] = fillvalue;
}

/* caller */
int **array = malloc((nx+1)*sizeof(int*));
array[0] = malloc((nx+1)*(ny+1)*sizeof(int));
for (i = 1; i < nx+1 ;i++)
array = array[i-1] + ny+1; /* save start address of each row */
fillinnumbers(3, 1, nx, 1, ny, array);
free(array[0]);
free(array);


Damn... Having spent 4 hours or so on this I think I made a program
using the above that works... But I would like to debug it using MSVS
2005 and found that array points to 0x003a4d58. I then click the + sign
and it shows me a value of 0x003a4db0. There's yet another +-sign so I
click on it and find the value -842150451. I don't know quite how to
interpret this since I've never worked with 2D-arrays like this so
please bear over with me and let me know how to understand these memory
numbers...


You've allocated two blocks of memory. The first is at 3a4d58 and will hold
a pointer vector with a pointer for each row, so its size is
number-of-rows*size-of-pointer.

The second is at 3a4db0 and holds the matrix, so its size is
rows*cols*sizeof(int).

The rows of the matrix are laid out one after the other, so
start address of row 0 = start address of block = 3a4db0
start address of row 1 = 3a4db0 + size of 1 row
where size of 1 row = number of columns * sizeof(int)
start address of row 2 = 3a4db0 + size of 2 rows (= start address of row 1
+ size of 1 row)
etc

and these addresses are stored in the vector as array[0], array[1],
array[2], etc

So the debugger shows
array = address of vector = 3a4d58
*array = array[0] = element 0 of vector = start address of row 0 = 3a4db0
**array = array[0][0] = -842150451 = uninitialised int data.
fillinnumbers() starts at array[1][1], so array[0][0] never gets used.

Since this is a 2D-array what's the easist way of seeing the memory
content at location array[2][2] for instance?

Watching array[2][2] works for me, but only after array[2] is assigned a
value.

If you've got 11 columns, array[0][2*11+2] should be equivalent.

Might be there's some
hand-calculation involved? I guess I'll have to do something like
0x003a4d58 + 2 rows + 2 columns and watch that memory address, right?

You'd be starting from the base of the matrix block, so for 11 columns it
would be
3a4db0 + (2*11 + 2)*sizeof(int)




[snip]
But you don't need to do any of that. Your compiler has the variable-length
array support from C99. This must be everybody's favourite improvement, but
the advantage will never be realised if everybody insists on making their
code back-portable to C90 for ever.

In C99 all you need is an extra parameter and a bit of clever syntax:

/* prototype */
void fillinnumbers(int, int, int, int, int, int, int array[][*]);

/* definition */
void fillinnumbers(int fillvalue, int startx, int stopx, int starty, int
stopy, int ncols, int array[][ncols])
{
for(i=startx; i<=stopx; i++)
for(j=starty; j<=stopy; j++)
array[j] = fillvalue;
}

/* caller */
int array[nx+1][ny+1];
fillinnumbers(3, 1, nx, 1, ny, ny+1, array);


This was actually the first thing I tried... I wanted to try this last
thing first, because it seemed very easy. But I got these for the line
"void fillinnumbers(int fillvalue, int startx, int"...

error C2057: expected constant expression
error C2466: cannot allocate an array of constant size 0
error C2087: 'array' : missing subscript


Since your compiler accepts
int array[nx+1][ny+1];
I assumed it had full support for VLAs, but perhaps it doesn't.
 
?

=?ISO-8859-15?Q?Martin_J=F8rgensen?=

Michael said:
Martin Jørgensen schrieb:



I assume ptd contains the result of a malloc() call.
Yep.



Usually, it is a good idea to put error messages to stderr, i.e.
fputs("Your error message here\n", stderr);
as this gives the user the choice whether to suppress or redirect
output and/or errors (i.e. stdout and/or stderr).

Since I've got a lot of malloc's (8-10) perhaps I could make a function:

checkPtr_error(%s location, %p pointer)
{
if (pointer == NULL)
{
fputs("Memory allocation failure (%s). Bye\n", location, stderr);
}
}

So I have something like:
int **array = malloc((nx+1)*sizeof(int*));
checkPtr_error("array", &array)
int **var1 = malloc((nx+1)*sizeof(int*));
checkPtr_error("var1", &var1)
int **var2 = malloc((nx+1)*sizeof(int*));
checkPtr_error("var2", &var2)
int **doubleptr = malloc((nx+1)*sizeof(double*));
checkPtr_error("doubleptr", &doubleptr)
etc.

The above is untested, but using a checkPtr_error function could save me
for typing some code, right?
This is the most drastic of all possible error treatments.
It may be better to
- try to salvage the situation by trying to allocate less memory
- terminate orderly, if that does not work/is not possible; this
includes writing out the output as far as it is ready, freeing
all resources used by your program.
- ... (whatever you can come up with, maybe even switching to a
less memory but more time consuming method).

Ok... I'll see what I can do.
By all means: Yes!
Always check the return value of malloc() and introduce reasonable
error handling. Check this error handling by demanding absurdly
much memory or changing if (ptd == NULL) to if (0 && ptd == NULL).
Writing out an error message and aborting is often what you see
in newsgroups but it is most of the time insufficient in real life.

Ok. I'll look at the other messages when I get home in the evening...


Best regards / Med venlig hilsen
Martin Jørgensen
 
?

=?ISO-8859-15?Q?Martin_J=F8rgensen?=

Martin said:
Michael Mair wrote: -snip-

Since I've got a lot of malloc's (8-10) perhaps I could make a function:

checkPtr_error(%s location, %p pointer)
{
if (pointer == NULL)
{
fputs("Memory allocation failure (%s). Bye\n", location, stderr);
}
}

So I have something like:
int **array = malloc((nx+1)*sizeof(int*));
checkPtr_error("array", &array)
int **var1 = malloc((nx+1)*sizeof(int*));
checkPtr_error("var1", &var1)
int **var2 = malloc((nx+1)*sizeof(int*));
checkPtr_error("var2", &var2)
int **doubleptr = malloc((nx+1)*sizeof(double*));
checkPtr_error("doubleptr", &doubleptr)
etc.

The above is untested, but using a checkPtr_error function could save me
for typing some code, right?


Well, could I do that? Does it work!?!?! Or should I forget about it?


-snip-
Why do you have a 0 in here: if(0 && ptd == NULL) instead of just if(ptd
== NULL) ?


Best regards / Med venlig hilsen
Martin Jørgensen
 
M

Michael Mair

Martin said:
Well, could I do that? Does it work!?!?! Or should I forget about it?

You could but I do not see much benefit.
Generating a good "location" may involve __FILE__, __LINE__ (, __func__
in C99), iteration count or something else to indicate "when and where"
allocation fails, i.e. you rather want to check for null pointers
_before_ generating "location".
However, wrapping the actual output into a separate function _can_
be a good idea. I.e.
if (NULL == ptr) {
/* generate location */
....
printErrAllocation(location, ptr);
}
Why do you have a 0 in here: if(0 && ptd == NULL) instead of just if(ptd
== NULL) ?

I did not think twice about it ;-(
Think
1 || ptd == NULL
(or "0 && ptd != NULL" for the other way round) instead.


Cheers
Michael
 
?

=?ISO-8859-1?Q?Martin_J=F8rgensen?=

Robin said:
-snip-

First: Thanks writing such an excellent explanation.
You've allocated two blocks of memory. The first is at 3a4d58 and will hold
a pointer vector with a pointer for each row, so its size is
number-of-rows*size-of-pointer.

Yeah, that is this one, right?

"int **number = malloc((nx+1)*sizeof(int*));"

The two stars ** means that it is a pointer to a pointer (to an
integer), right?

I can easily picture myself a 1-dimensional array pointer, having seen
such one in a figure in my C-programming book...

I think I would understand it more easily if there exists a graphical
explanation somewhere on the net - perhaps somebody has a link?
The second is at 3a4db0 and holds the matrix, so its size is
rows*cols*sizeof(int).

That is a "single" pointer to some integers like here, I assume:

number[0] = malloc((nx+1)*(ny+1)*sizeof(int));
The rows of the matrix are laid out one after the other, so
start address of row 0 = start address of block = 3a4db0
start address of row 1 = 3a4db0 + size of 1 row
where size of 1 row = number of columns * sizeof(int)
start address of row 2 = 3a4db0 + size of 2 rows (= start address of row 1
+ size of 1 row)
etc
Ok.

and these addresses are stored in the vector as array[0], array[1],
array[2], etc

Let me be sure I understand this:

array[0] = start address of block = 3a4db0
array[1] = array[0] + size of 1 row
array[2] = array[1] + size of 1 row

It that correct or not?
So the debugger shows
array = address of vector = 3a4d58
*array = array[0] = element 0 of vector = start address of row 0 = 3a4db0
**array = array[0][0] = -842150451 = uninitialised int data.

Hmmmmmm. I want to see my 2D-array in the debugger. I now successfully
made a program like this:

count = 0;
for(i=0; i<=nx; i++) /* go through all rows */
{
for(j=0; j<=ny; j++){array[j] = ++count;}
printout(0, nx, 0, ny, array);
}

Calling printout gives me the expected values (all are double values):

1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0
8.0, 9.0, 10, 11, 12, 13, 14
15, 16, 17, 18, 19, 20, 21
22, 23, 24, 25, 26, 27, 28
29, 30, 31, 32, 33, 34, 35
36, 37, 38, 39, 40, 41, 42
43, 44, 45, 46, 47, 48, 49

So it works. I just want to be able to debug just by watching things in
memory. Moving my mouse pointer over array gives me (probably new memory
location compared to yesterday):

1) 0x003a4d60. Clicking the "+"-sign gives me:
2) 0x003a4db8. And clicking the "+"-sign again gives me the first array
element:
3) 1.0!

Hooray... My memory dump looks like this:

0x003A4DB8 00 00 00 00 00 00 f0 3f 00 00 00 00 00 00 00 40 00 00
.......?.......@..
0x003A4DCA 00 00 00 00 08 40 00 00 00 00 00 00 10 40 00 00 00 00
......@.......@....
0x003A4DDC 00 00 14 40 00 00 00 00 00 00 18 40 00 00 00 00 00 00
....@.......@......
....
....

That is double. As wrote earlier: I want see my numbers array 1 to 49? I
don't remember if a double value (double pointer?) takes 8 bytes but if
so, I remember that the first value (00 00 00 00 00 00 f0 3f) must be
something like: 3ff0 or something. Please tell me how to convert these
bytes from the memory dump to a memory location...

My guess is that I should look 0x003a4db8 and find out where it points
to (something with 3ff0 - please tell me, I'm not sure). And looking
*there* I hope to find the first array element: 1.0......?

Right or wrong?

I would really appreciate a solution/formula/step-by-step instruction
here, *indeed*. :)
fillinnumbers() starts at array[1][1], so array[0][0] never gets used.


Since this is a 2D-array what's the easist way of seeing the memory
content at location array[2][2] for instance?


Watching array[2][2] works for me, but only after array[2] is assigned a
value.

Doesn't work here. I can only see the first value "1.0".
If you've got 11 columns, array[0][2*11+2] should be equivalent.


Might be there's some
hand-calculation involved? I guess I'll have to do something like
0x003a4d58 + 2 rows + 2 columns and watch that memory address, right?


You'd be starting from the base of the matrix block, so for 11 columns it
would be
3a4db0 + (2*11 + 2)*sizeof(int)

I'll have to get back to that and try it (understand) it later :)
But you don't need to do any of that. Your compiler has the
variable-length
array support from C99. This must be everybody's favourite improvement,
but
the advantage will never be realised if everybody insists on making
their
code back-portable to C90 for ever.

In C99 all you need is an extra parameter and a bit of clever syntax:

/* prototype */
void fillinnumbers(int, int, int, int, int, int, int array[][*]);

/* definition */
void fillinnumbers(int fillvalue, int startx, int stopx, int starty, int
stopy, int ncols, int array[][ncols])
{
for(i=startx; i<=stopx; i++)
for(j=starty; j<=stopy; j++)
array[j] = fillvalue;
}

/* caller */
int array[nx+1][ny+1];
fillinnumbers(3, 1, nx, 1, ny, ny+1, array);


This was actually the first thing I tried... I wanted to try this last
thing first, because it seemed very easy. But I got these for the line
"void fillinnumbers(int fillvalue, int startx, int"...

error C2057: expected constant expression
error C2466: cannot allocate an array of constant size 0
error C2087: 'array' : missing subscript



Since your compiler accepts
int array[nx+1][ny+1];
I assumed it had full support for VLAs, but perhaps it doesn't.


nx and ny was not variables. They were #define'd if that makes any
difference...


Best regards / Med venlig hilsen
Martin Jørgensen
 
?

=?ISO-8859-15?Q?Martin_J=F8rgensen?=

Michael said:
Martin Jørgensen schrieb: -snip-



You could but I do not see much benefit.
Generating a good "location" may involve __FILE__, __LINE__ (, __func__
in C99), iteration count or something else to indicate "when and where"
allocation fails, i.e. you rather want to check for null pointers
_before_ generating "location".

Perhaps a stupid question, but what's those __FILE__, __LINE__ (,
__func__ things?
However, wrapping the actual output into a separate function _can_
be a good idea. I.e.
if (NULL == ptr) {
/* generate location */
....
printErrAllocation(location, ptr);
}

Well, I think you're much more advanced than me when you think about
generating a location... My "location" is just a char-array:

int **array = malloc((nx+1)*sizeof(int*));
checkPtr_error("array", &array)

Here "array" is the "location" and "array" will be printed if this is
the location where memory couldn't be allocated.
I did not think twice about it ;-(
Think
1 || ptd == NULL
(or "0 && ptd != NULL" for the other way round) instead.

I might be stupid or too unexperienced with C-programming but I still
don't get that. The following works, right: if (NULL == ptr) {.....}

So doing either:

1 || ptd == NULL

or:

"0 && ptd != NULL"

I don't understand what that does... In the first case: if(1 || ptd ==
NULL) would always give 1, becuase || = logical "or" right? 1 = true, AFAIR.

In the second case: if(0 && ptd != NULL) that would always give 0
because && means logical "and", right?


Best regards / Med venlig hilsen
Martin Jørgensen
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top