Thread: Readability issues with function declarations and arrays as parameters.

  1. #1
    Registered User
    Join Date
    Sep 2011
    Location
    Athens , Greece
    Posts
    357

    Readability issues with function declarations and arrays as parameters.

    Hello....assume that we have :

    Code:
      void fill_array( int n , int arr[*]);
    Kings says that a declaration of

    Code:
      void fill_array( int , int []);
    Is not a good choice because you can't see the relation between n and length of array.... for me is more convenient though to omit the names of parameters one reason is I take the flexilibity to name the variables in the definition with any name that I want there are some legimitate reasons to omit parameter names as King writes later on his book.

    Another issue is the symbol (*) Kings says that provides a clue that the length of the array is related to parameters that come earlier in the list ... what is this? a convention among the programmers? I mean the symbol * ?

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Mr.Lnx
    for me is more convenient though to omit the names of parameters one reason is I take the flexilibity to name the variables in the definition with any name that I want
    Why would you want to do that?

    Quote Originally Posted by Mr.Lnx
    there are some legimitate reasons to omit parameter names as King writes later on his book.
    You are probably thinking of a case where the parameter is unused, but kept for future use or to preserve a legacy interface. However, that would be different from using differing names in a declaration and the definition for the same parameter.

    Quote Originally Posted by Mr.Lnx
    Another issue is the symbol (*) Kings says that provides a clue that the length of the array is related to parameters that come earlier in the list ... what is this? a convention among the programmers? I mean the symbol * ?
    It is not convention, but rather syntax that says that the parameter is of some variable length array type, where the size is not specified.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    May 2010
    Posts
    4,633
    For the function prototype I usually like the variable name present. However I usually will make these names meaningful. For the actual function implementation I sometimes use different names.

    Code:
    void fill_array(int array_size, int *array);
    or 
    void fill_array(int array_size, int array[]);
    
    void fill_array(int size, int *arr)
    {
    
    }
    Jim

  4. #4
    Registered User
    Join Date
    Sep 2011
    Location
    Athens , Greece
    Posts
    357
    Quote Originally Posted by laserlight View Post
    Why would you want to do that?
    One reason As I read from Kings book is

    Ommiting parameter names in prototypes is typically done for defensive purposes.If a macro happens to have the same name as a parameter , the parameter name will be replaced during preprocessing , thereby damaging the prototype in which it appears. This isn't likely to be a problem in a small program writeen by one person but can occur in large applications writen by many people.

    But I can't understand because :

    Code:
    #include <stdio.h>
    #define x 100
    int foo(int );
    
    
    int main( void )
    {
    
    int x = 2;
    
    printf("%d" , foo(x)); //3
    
    	return 0;
    }
    int foo( int x )
    {
    	
    return x+1;
    }
    On this example we omit the name of x in the prototype but we must use it in the definition of the function so .... there is a problem too because preprocessor replaces the appear of x wherever ii exists in the source code. I can't understand what is the point of King here....

    To be sincere is more natural and convenient to me when I write code keep the names away from prototypes.

  5. #5
    Registered User
    Join Date
    Sep 2011
    Location
    Athens , Greece
    Posts
    357
    Μaybe King means something like :

    Code:
    #include <stdio.h>
    #define x 100
    int foo(int x);  // PROBLEM HERE change to  int foo(int ); 
    
    int main( void )
    {
    
    int y = 2;
    
    printf("%d" , foo(y)); //3
    
    	return 0;
    }
    int foo( int y )
    {
    	
    return y+1;
    }
    Last edited by Mr.Lnx; 06-06-2013 at 06:18 PM.

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Mr.Lnx
    On this example we omit the name of x in the prototype but we must use it in the definition of the function so .... there is a problem too because preprocessor replaces the appear of x wherever ii exists in the source code. I can't understand what is the point of King here....
    A function prototype will typically be placed in a header file, whereas a function definition will likely be in a source file. So, the inclusion of another header might introduce a macro name that conflicts... but if you follow the convention of fully capitalising macro names, then this is a non-issue.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #7
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    Ommiting parameter names in prototypes is typically done for defensive purposes.If a macro happens to have the same name as a parameter , the parameter name will be replaced during preprocessing , thereby damaging the prototype in which it appears. This isn't likely to be a problem in a small program writeen by one person but can occur in large applications writen by many people.
    This is an entirely bogus reason as you've already spotted. If the parameter name would be screwed up in the prototype, then it's also going to get screwed up in the same way in the function definition.
    By convention, macro names (and only macro names) are written in UPPERCASE, so the problem of unexpected prototype parameter name substitution never applies.

    > To be sincere is more natural and convenient to me when I write code keep the names away from prototypes.
    Which would you rather see in a header file?
    int findsubstring ( char*, char* );
    vs.
    int findsubstring ( char*needle, char*haystack );

    Personally, I prefer the second, since it's instantly obvious which way round the parameters are. A bare prototype means you're off trying to find the documentation (or the source code).

    Further, if you wrote
    Code:
    int findsubstring ( char*needle, char*haystack ) {
      // code goes here
    }
    then it's a simple copy/paste to make the prototype
    int findsubstring ( char*needle, char*haystack );

    Why waste further edit time (and the chance of screwing up the edit in some way) just to make the prototype less readable?

    > Another issue is the symbol (*) Kings says that provides a clue that the length of the array is related to parameters that come earlier in the list ... what is this?
    To be honest, I thought it was a mistake until I looked it up in the standard.
    Personally, I can't see what it does which is of any benefit over just leaving the size empty.
    I mean, "an earlier parameter" doesn't mean a thing if you're faced with
    void func ( int n, int len, int arr[*] );
    or worse
    void func ( int, int, int[*] );

    I wonder which int controls the array length here?
    Every competent C programmer knows that arrays are just pointers, so there has to be another parameter specifying the size of the array if the function has any hope of being written in a safe manner.

    The compiler simply doesn't care about the left-most dimension in function array parameters.
    Code:
    #include<stdio.h>
    #include<stdlib.h>
    
    void fill_array1( int n, int arr[*]);
    void fill_array2( int n, int arr[]);
    void fill_array3( int n, int arr[5]);
    void fill_array4( int n, int arr[n]);
    void fill_array5( int n, int *arr);
    
    void fill_array1( int n, int arr[/* can't use a * here? */] ) {
      printf("%zd\n", sizeof(arr) );
      for ( int i = 0 ; i < n ; i++ ) arr[i] = i;
    }
    void fill_array2( int n, int arr[] ) {
      printf("%zd\n", sizeof(arr) );
      for ( int i = 0 ; i < n ; i++ ) arr[i] = i;
    }
    void fill_array3( int n, int arr[5] ) {
      printf("%zd\n", sizeof(arr) );
      for ( int i = 0 ; i < n ; i++ ) arr[i] = i;
    }
    void fill_array4( int n, int arr[n] ) {
      printf("%zd\n", sizeof(arr) );
      for ( int i = 0 ; i < n ; i++ ) arr[i] = i;
    }
    void fill_array5( int n, int *arr ) {
      printf("%zd\n", sizeof(arr) );
      for ( int i = 0 ; i < n ; i++ ) arr[i] = i;
    }
    
    int main()
    {
      int a[20];
      fill_array1(20,a);
      fill_array2(20,a);
      fill_array3(20,a);
      fill_array4(20,a);
      fill_array5(20,a);
      return 0;
    }
    
    $ gcc -std=c99 -W -Wall bar.c
    $ ./a.out 
    8
    8
    8
    8
    8
    > bar.c:10:1: error: ‘[*]’ not allowed in other than function prototype scope
    This shows a couple of things.
    1. the[*] notation is a pointless exercise away from copy/pasting definition to prototype.
    2. no matter how you write your array parameter, it won't magically transform it into something else - it is and remains just a pointer.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  8. #8
    Registered User ledow's Avatar
    Join Date
    Dec 2011
    Posts
    435
    Put the variable name in the prototype.
    Use an IDE that replaces all occurrences of the variable name (even in the prototype).
    When you want to change the name, change it using the IDE so it's aware that it needs to change all occurrences, including the prototype.

    I find prototypes without any variable names absolutely 100% useless. You have to go to the function definition to find out what the hell they do. If I wanted to do that, I wouldn't have bothered looking at the prototype first.

    Think of headers files and function prototypes as the "interface" to your code. If another programmer (or yourself, ten years later) comes along and looks at the code, they should be able to USE the code and plug into it with nothing more than the header file (this is why, when libraries are shipped on any OS, they give you the library - dll, so or whatever - and the header file. That's ALL you need, if they are written properly.) The programmer generally has no need to see your function definition or play with the code inside. In fact, in most cases they won't want to. But if you have a well-defined interface and a well-documented header file, they never need to know HOW your code works, just how to talk to it.

    In this case, the header file on its own is damn useless. Even with comments, you have to zip back and forth and work out if the fifth parameter is the array index or the one next to it that's also an int. Whereas, with good variable names inside a clean header file you probably won't even need the comments.

    Go look at how any big-name library distributes it's header file. 99% of the time you'll find proper variable names in there.

    (e.g.:

    Code:
    SDL_GFXPRIMITIVES_SCOPE int aacircleColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Uint32 color);

    - Compiler warnings are like "Bridge Out Ahead" warnings. DON'T just ignore them.
    - A compiler error is something SO stupid that the compiler genuinely can't carry on with its job. A compiler warning is the compiler saying "Well, that's bloody stupid but if you WANT to ignore me..." and carrying on.
    - The best debugging tool in the world is a bunch of printf()'s for everything important around the bits you think might be wrong.

  9. #9
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Quote Originally Posted by Salem View Post
    If the parameter name would be screwed up in the prototype, then it's also going to get screwed up in the same way in the function definition.
    By convention, macro names (and only macro names) are written in UPPERCASE, so the problem of unexpected prototype parameter name substitution never applies.
    QFT!

    I'd also like to add that the chance of this happening is miniscule, but the chance of passing the wrong parameters because of the missing names is significant.

    And finally, the name helps with more than just which parameter is which, e.g. it can also help identify what the units are, so that you don't pass in a value in kms when the function is expecting miles. You woudn't want to be responsible for crashing a lander on mars now would you?
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  10. #10
    Registered User
    Join Date
    Sep 2011
    Location
    Athens , Greece
    Posts
    357
    Quote Originally Posted by laserlight View Post
    A function prototype will typically be placed in a header file, whereas a function definition will likely be in a source file. So, the inclusion of another header might introduce a macro name that conflicts... but if you follow the convention of fully capitalising macro names, then this is a non-issue.
    Yes you are right... the names are conflicted but I can't understand why King gives such a reason on page 211.

    @Salem I don't disagree with you according to * symbols. Personally I leave the size blank without * symbol exactly the reason that you show above (an array is exactly a pointer in a function definition). They are equals at this point of the code.

    Code:
    #define MAXELEMS  100
    
    void foo( int array[] )
    {
            for (int i=0; i < MAXELEMS; i++)
                    //...
    }
    Finally you can drop the length as in parameter away from function... passing only the array and using later the directive MAXELEMS.
    Last edited by Mr.Lnx; 06-07-2013 at 04:15 AM.

  11. #11
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Mr.Lnx
    Finally you can drop the length as in parameter away from function... passing only the array and using later the directive MAXELEMS.
    That is typically a bad idea, unless you are really certain that the function will not be used with an array of differing number of elements. Furthermore, in some cases, only part of the array might be used.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  12. #12
    Registered User
    Join Date
    Sep 2011
    Location
    Athens , Greece
    Posts
    357
    Quote Originally Posted by laserlight View Post
    That is typically a bad idea, unless you are really certain that the function will not be used with an array of differing number of elements. Furthermore, in some cases, only part of the array might be used.
    No. This will be work exactly with MAXELEMS-1 elements. That is why I am using the preprocessing directive

    In the case that you don't pass the length as extra argument...
    It is more fast and readable without the necessity of extra checks because the function does not know what argument will be passed by programmer.
    Do you have different opinion about that?
    Last edited by Mr.Lnx; 06-07-2013 at 04:56 AM.

  13. #13
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Mr.Lnx
    No. This will be work exactly with MAXELEMS-1 elements.
    If you are really sure of that, then fine. The thing is, your function is now tightly coupled to MAXELEMS. You need to be aware of this before you jump into using what appears to be a simpler interface at first glance.

    Quote Originally Posted by Mr.Lnx
    That is why I am using the preprocessing directive
    No, MAXELEMS gives a name to what would otherwise be a magic number. That is a Good Thing, but it does not mean that you must directly use MAXELEMS whenever you want to iterate over the associated array.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  14. #14
    Registered User migf1's Avatar
    Join Date
    May 2013
    Location
    Athens, Greece
    Posts
    385
    Quote Originally Posted by Mr.Lnx View Post
    No. This will be work exactly with MAXELEMS-1 elements. That is why I am using the preprocessing directive
    I think that what laserlight says is that this approach is less flexible, because it makes it harder to manipulate only a (starting) part of the array, with the length of that part not being the same each time we call the function.

    Personally I use both approaches, depending on the task (there are cons and pros, for example the approach you presented saves us at least one sanity check inside the function )

  15. #15
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    It is more fast and readable without the necessity of extra checks because the function does not know what argument will be passed by programmer.
    Do you have different opinion about that?
    I have a very strong opinion about that. Ready?

    You are dead wrong.

    I know that what you think is fast has nothing to do with actually being fast. And while you say it is more readable, why is it more readable?

    Code:
    void foo (int something[], size_t somethingSize);
    All you need to know to understand this is what a size_t type variable is, and what it represents. C makes both of these things obvious with its grammar rules. The type of a parameter must be present in the parameter list, like above. The optional but conventionally used parameter name explains what it is used for.

    I would recommend that you don't confuse more readable code with code that you refuse to read.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Function declarations
    By ssharish2005 in forum C Programming
    Replies: 9
    Last Post: 10-09-2007, 07:06 AM
  2. Few questions: Bytes, Arrays, Declarations, and Buff
    By viciousv322 in forum C Programming
    Replies: 7
    Last Post: 12-15-2005, 07:54 PM
  3. class function declarations
    By HSC140 in forum C++ Programming
    Replies: 4
    Last Post: 03-25-2002, 11:23 PM
  4. Arrays as function parameters
    By Flake in forum C++ Programming
    Replies: 2
    Last Post: 03-07-2002, 02:05 AM
  5. complex if statement readability
    By mlupo in forum C Programming
    Replies: 3
    Last Post: 11-19-2001, 08:54 PM