Newsgroups: comp.lang.c Path: utzoo!utgpu!news-server.csri.toronto.edu!helios.physics.utoronto.ca!aurora.physics.utoronto.ca!neufeld From: neufeld@aurora.physics.utoronto.ca (Christopher Neufeld) Subject: Re: Novice C question Message-ID: <1991Apr16.033331.5408@helios.physics.utoronto.ca> Sender: news@helios.physics.utoronto.ca (News Administrator) Nntp-Posting-Host: aurora.physics.utoronto.ca Organization: University of Toronto Physics/Astronomy/CITA References: <31969@usc> Date: Tue, 16 Apr 1991 03:33:31 GMT In article <31969@usc> ajayshah@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@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!"