Path: csiph.com!eternal-september.org!feeder.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail From: Keith Thompson Newsgroups: comp.lang.c Subject: Re: A glitch regarding the usual malloc() idiom Date: Fri, 05 Aug 2016 12:07:15 -0700 Organization: None to speak of Lines: 101 Message-ID: References: <4cd22745-22ad-4ac7-bdba-39ffa1c75e13@googlegroups.com> <48bfec8e-1f8b-4a7d-9de9-2f4b203efa88@googlegroups.com> <29458e01-2a24-4ce7-b856-87988b674c15@googlegroups.com> <592d7153-ee57-414e-b340-04027edd4098@googlegroups.com> <43e2dbcd-4759-4e2c-ad08-20d7a29556f1@googlegroups.com> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Injection-Info: mx02.eternal-september.org; posting-host="945944de09706c9b4e29b53c9d2efdc2"; logging-data="10809"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1+dCPzkQvg2t6ghDQqHg3oN" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.1 (gnu/linux) Cancel-Lock: sha1:HmAJHY02xbtjPE0fXhiNPY0DtM0= sha1:ifPkzocQQB1lfnNrb6VV56Ff61Y= Xref: csiph.com comp.lang.c:91759 BartC writes: > On 05/08/2016 18:30, Keith Thompson wrote: > >> The advantages of writing, for example, >> p = malloc(N * sizeof *p); >> rather than >> p = malloc(N * sizeof (type_that_p_points_to)); > >> are that (a) when you read that line, you can see that it >> correctly allocates an array of N elements without having to look >> up the definition of p (and possibly count the "*"s if it's a >> pointer-to-pointer), and (b) *that line* remains correct if the >> type of p changes during later maintenance. >> >> I actually consider the first point to be more important, but >> opinion can differ on that. >> >> You've argued for some alleged advantages of using the type name. >> I found those arguments unconvincing and insufficient to override >> the advantages of using an expression. > > I've listed the advantages of using the type elsewhere, but I can't > find it (I can't remember what thread it was). > > They're more obvious when the variable name is longer: > > int* arrayptr = malloc(N * sizeof(*arrayptr)); // (1) > > int* arrayptr = malloc(N * sizeof(int)); // (2) > > Both styles require you to write something on the rhs that matches > something on the lhs. You've moved the goalposts. The original example was a *statement* that allocates memory for an existing pointer; the declaration of the pointer might not be immediately visible. (IDEs and smart editors can make it easier to find the declaration, but not having to find it at all is even easier.) Your new example is a *declaration* that initializes a newly defined pointer. That's preferable when it's possible, but sometimes it isn't. Here's another example: int **ptr = malloc(N * sizeof (int*)); For a pointer-to-pointer (for however many levels), the type operand of the sizeof has to have exactly one fewer "*"s than the type of the pointer. That's not too hard to get right, but writing int **ptr = malloc(N * sizeof *ptr); is simpler and more consistent. > You're implying that it is easier if this is the variable name, than > the name of its type. Yes. > However there are likely to be many more different variable names than > there are types (especially as often the type will be a standard type > like in my example). > > These increase the chances of inadvertently using the wrong variable > name with (1). That's never been a problem for me. Has it ever been a problem for you, or are you just reaching for ways it *might* go wrong? > If a line like (1) is copied and pasted elsewhere, then edited to > create a new pointer, you have to remember to change both names: > > int* arrayptr2 = malloc(N * sizeof(*arrayptr)); Yes. Hopefully you'll be using meaningful names that are easily distinguishable rather than something artificial like "arrayptr" and "arrayptr2". (And of course the compiler will catch it if "arrayptr" doesn't happen to be visible at that point.) > This may still work by chance, but it's wrong. Doing it with (2): > > int* arrayptr2 = malloc(N * sizeof(int)); > > only requires one change when the type is the same as it often is. And when the type isn't the same, the compiler won't tell you you've made a mistake; you'll just allocate the wrong size *and it won't be obvious by reading the line of code that does the allocation*. I don't want the correctness of my code to rely on the type "usually" being the same. No programming idiom will prevent all possible errors. If writing the same expression twice is too much of a burden, you can always write a macro. (Personally I wouldn't bother.) -- Keith Thompson (The_Other_Keith) kst-u@mib.org Working, but not speaking, for JetHead Development, Inc. "We must do something. This is something. Therefore, we must do this." -- Antony Jay and Jonathan Lynn, "Yes Minister"