Path: utzoo!utgpu!news-server.csri.toronto.edu!mailrus!cs.utexas.edu!swrinde!ucsd!pacbell.com!decwrl!ucbvax!bloom-beacon!adam!scs From: scs@adam.mit.edu (Steve Summit) Newsgroups: comp.lang.c Subject: Changes to Answers to Frequently Asked Questions (FAQ) on comp.lang.c Message-ID: <1990Aug1.040206.19501@athena.mit.edu> Date: 1 Aug 90 04:02:06 GMT Sender: daemon@athena.mit.edu (Mr Background) Reply-To: scs@adam.mit.edu (Steve Summit) Organization: Thermal Technologies, Inc. Lines: 193 This article contains the changes between the previous posting of the frequently-asked questions list (July 18) and the new one (coming up next). (These diffs have been edited for readability and are not suitable for the patch program.) 178,179c166,167 < doing so sends the wrong stylistic message. (The ANSI #definition < of NULL is allowed to be (void *)0, which will not work in non- --- > doing so sends the wrong stylistic message. (ANSI allows the > #definition of NULL to be (void *)0, which will not work in non- 301a286,291 > 10. But I once used a compiler that wouldn't work unless NULL was used. > > A: This compiler was broken. In general, making decisions about a > language based on the behavior of one particular compiler is likely > to be counterproductive. 416c406,410 < formal argument declarations, nowhere else. --- > formal parameter declarations, nowhere else. If this conversion > confuses you, don't use it; many people have concluded that the > confusion it causes outweighs the small advantage of having the > declaration "look like" the call and/or the uses within the > function. 446a441,528 > 17. My compiler complained when I passed a two-dimensional array to a > routine expecting a pointer to a pointer. > > A: The rule by which arrays decay into pointers is not applied > recursively. An array of arrays (i.e. a two-dimensional array in C) > decays into a pointer to an array, not a pointer to a pointer. > Pointers to arrays are confusing, and it is best to avoid them. > (The confusion is heightened by incorrect compilers, including some > versions of pcc and pcc-derived lint's, which incorrectly accept > assignments of multi-dimensional arrays to multi-level pointers.) > If you are passing a two-dimensional array to a function: > > int array[YSIZE][XSIZE]; > f(array); > > the function's declaration should match: > f(int a[][XSIZE]) {...} > or > f(int (*a)[XSIZE]) {...} > > In the first declaration, the compiler performs the usual implicit > rewriting of "array of array" to "pointer to array;" in the second > form the pointer declaration is explicit. The called function does > not care how big the array is, but it must know its shape, so the > "column" dimension XSIZE must be included. In both cases the number > of "rows" is irrelevant, and omitted. > > If a function is already declared as accepting a pointer to a > pointer, an intermediate pointer would need to be used when > attempting to call it with a two-dimensional array: > > int *ip = &a[0][0]; > g(&ip); > ... > g(int **ipp) {...} > > Note that this usage is liable to be misleading (if not incorrect), > since the array has been "flattened" (its shape has been lost). > > 18. How do I declare a pointer to an array? > > A: Usually, you don't want one. Think about using a pointer to one of > the array's elements instead. Arrays of type T decay into pointers > to type T, which is convenient; subscripting or incrementing the > resultant pointer accesses the individual members of the array. > True pointers to arrays, when subscripted or incremented, step over > entire arrays, and are generally only useful when operating on > multidimensional arrays. (See the question above.) > > 19. How can I dynamically allocate a multidimensional array? > > A: It is usually best to allocate an array of pointers, and then > initialize each pointer to a dynamically-allocated "row." The > resulting "ragged" array often saves space, although it may not be > contiguous in memory as a real array would be. > > int **array = (int **)malloc(nrows * ncolumns * sizeof(int *)); > for(i = 0; i < nrows; i++) > array[i] = (int *)malloc(ncolumns * sizeof(int)); > > (In "real" code, of course, malloc's return value should be > checked.) > > You can keep the array's contents contiguous, while losing the > ability to have rows of varying and different lengths, with a bit of > explicit pointer arithmetic: > > int **array = (int **)malloc(nrows * ncolumns * sizeof(int *)); > array[0] = (int *)malloc(nrows * ncolumns * sizeof(int)); > for(i = 1; i < nrows; i++) > array[i] = array[0] + i * ncolumns; > > In either case, the elements of the dynamic array can be accessed > with normal-looking array subscripts: array[i][j]. > > If the double indirection implied by the above scheme is for some > reason unacceptable, you can simulate a two-dimensional array with a > single, dynamically-allocated one-dimensional array: > > int *array = (int *)malloc(nrows * ncolumns * sizeof(int)); > > However, you must now perform subscript calculations manually, > accessing array[i, j] with array[i * ncolumns + j]. (A macro can > hide the explicit calculation, but invoking it then requires > parentheses and commas which don't look exactly like > multidimensional array subscripts.) 471c553,554 < value 4. --- > value 4. ANSI allows compilers to reject code which contains such > ambiguous or undefined side effects. 476c559 < 18. But what about the &&, ||, and ?: operators? --- > 21. But what about the &&, ||, ?:, and comma operators? 549a633,635 > (In this case, it would be clearest to change the old-style > definition to use double as well). 660c745,746 < Note the cast on the last argument. --- > Note the cast on the last argument. (Also note that the caller must > free the returned, malloc'ed storage.) 713a799,804 > 31. How can I write a function analogous to scanf? > > A: Unfortunately, vscanf and the like are not standard. You're on your > own. 794a885,907 > 35. You can't use dynamically-allocated memory after you free it, can > you? > > A: No. Some early man pages for malloc stated that the contents of > freed memory was "left undisturbed;" this ill-advised guarantee is > not universal and is not required by ANSI. > > Few programmers would use the contents of freed memory deliberately, > but it is easy to do so accidentally. Consider the following > (correct) code for freeing a singly-linked list: > > struct list *listp, *nextp; > for(listp = base; listp != NULL; listp = nextp) { > nextp = listp->next; > free((char *)listp); > } > > and notice what would happen if the more-obvious loop iteration > expression listp = listp->next were used, without the temporary > nextp pointer. 885,889c1000,1004 < #define offsetof(type, mem) ((size_t) \ < ((char *)&(((type) *) 0)->mem - (char *)&(((type) *) 0))) < < This implementation is not 100% portable; some compilers may refuse < to accept it. --- > #define offsetof(type, mem) ((size_t) \ > ((char *)&((type *) 0)->mem - (char *)((type *) 0))) > > This implementation is not 100% portable; some compilers may > legitimately refuse to accept it. 1125a1239,1244 > Operating system specific questions are not appropriate for > comp.lang.c . Several common questions are answered in frequently- > asked questions postings in the comp.unix.questions and > comp.sys.ibm.pc newsgroups. 1265a1382,1391 > 62. Where can I get copies of all these public-domain programs? > > A: If you have access to Usenet, see the regular postings in the > comp.sources.unix and comp.sources.misc newsgroups, which describe, > in some detail, the archiving policies and how to retrieve copies. > Otherwise, you can try anonymous ftp and/or uucp from a central, > public-spirited site, such as uunet.uu.net, but this article cannot > track or list all of the available sites and how to access them.