Novice C question

Christopher Neufeld neufeld at aurora.physics.utoronto.ca
Tue Apr 16 13:33:31 AEST 1991


In article <31969 at usc> ajayshah at almaak.usc.edu (Ajay Shah) writes:
>
>1	double *dvector(nl,nh)
>2	int nl,nh;
>3	{
>4	        double *v;
>5	
>6	        v=(double *)malloc((unsigned) (nh-nl+1)*sizeof(double));
>7	        if (!v) nrerror("allocation failure in dvector()");
>8	        return v-nl;
>9	}
>
>It's supposed to be a function which allocates a vector of
>doubles.  My interpretation of nl and nh is: they're array
>indexes.  If you want to allocate an array going from 5 to 10,
>you would say p = dvector(5, 10).
>
   Yes, that's right. Memory is allocated for p[5] to p[10]. Memory
outside these points is not yours, and will usually crash the machine if
overwritten.

>Question: what is happening on line 8?  Why is he not just
>returning v (a pointer)?  What is the meaning of subtracting nl
>(an int) from v without any casting?
>
   Subtracting or adding an integer to a pointer has a well-defined
meaning. Consider:
  my_typedef *p1, *p2;
where 'my_typedef' is any arbitrary data structure.
If one defines:
p2 = p1 - n;    /* 'n' is an integer  */
Then the pointer 'p2' points in memory to a location earlier than 'p1'
in memory by an amount   n * sizeof(my_typedef)
OK, this looks pointless so far, since that memory might not be
reserved, or might be reserved for something completely different, like
the integer variable 'n'.
   Here's the fun part. When the compiler sees  p1[j] it evaluates it as
*(p1+j). The addition of the integer 'j' means the same thing it meant
above, it advances in memory by an amount   j * sizeof(*p1)

   So, an example. If you have a conventionally defined array, and a
pointer, such as:
float arr[3], *myvec;
and I assign:
myvec = arr - 1;

then the following are true:
myvec[0]  is undefined and dangerous to use, as you step on memory.
myvec[1] == arr[0]
myvec[2] == arr[1]
myvec[3] == arr[2]
arr[3]  is undefined and dangerous to use.

   To answer your question, the code fragment you asked about creates a
pointer 'v' to the beginning of an array whose indices lie between '0'
and 'nh-nl' inclusive. The 'return v-nl;' instruction returns a pointer
whose [nl] entry is the [0] entry of the 'v' just defined.

   I should mention that there is one exception that I know of, and
probably a few other people can provide. The rule is less simple for
multi-dimensional arrays defined in the conventional manner:
float arr[N1][N2][N3];
Now, when the compiler sees  arr[i][j][k] it evaluates:
*(arr + ((i * N2) + j) * N3 +k)
However, if I have:
float ***myarr;
then when the compiler sees myarr[i][j][k] it evaluates:
*(*(*(myarr+i)+j)+k)
Note that this definition takes less CPU usually, and eats a bit more
memory. It's also a bit easier to use in passing to functions because
the function doesn't have to be told the dimensions 'N2' and 'N3', which
it obviously needs for the first definition.


-- 
 Christopher Neufeld....Just a graduate student  | Flash: morning star seen
 neufeld at aurora.physics.utoronto.ca    Ad astra! | in evening! Baffled
 cneufeld@{pnet91,pro-cco}.cts.com               | astronomers: "could mean
 "Don't edit reality for the sake of simplicity" | second coming of Elvis!"



More information about the Comp.lang.c mailing list