View Single Post
Old 24th November 2011
ocicat ocicat is offline
Administrator
 
Join Date: Apr 2008
Posts: 3,318
Default

Quote:
Originally Posted by Daffy View Post
Comments about the structure of the code are also welcome.
  1. Code:
    struct tag_t {
    	char artist[LEN];
    	char album[LEN];
    	char year[LEN];
    	char genre[LEN];
    	char track[LEN];
    } taglist;
    This creates a global instance of the structure accessible from anywhere. While there are times that global variables are useful & sometimes even necessary in C programming (given C's limited scoping implementation...), use it sparingly. taglist is the name of the global instance. Consider the following as an alternative:
    Code:
    struct tag_t {
    	char artist[LEN];
    	char album[LEN];
    	char year[LEN];
    	char genre[LEN];
    	char track[LEN];
    };
    int main()
    {
        struct tag_t taglist;
    }
    This limits the scope of taglist to exist only within function main().

  2. Code:
    /* ... */
    void remove_enter( char *s )	/* function to remove enter from stdin */
    {
    	s[strcspn( s, "\n" )] = '\0';
    }
    
    int main(int argc, char *argv[])
    {
    /* ... */
    While it is not required nor a convention that main() be the first function in a file, many programmers do so. However if main() calls other user-defined functions defined in the same file, the compiler may give a warning that it does not understand how to check the function's parameter list unless the function's body has already been seen.

    The solution (& the point I want to make here...) is to use function prototypes. This keeps the compiler happy by providing the parameter list to the function before it is first called or defined. As an example using your earlier code:
    Code:
    /* ... */
    void remove_enter(char *s);
    
    int main(int argc, char *argv[])
    {
        /* ... */
    }
    
    void remove_enter(char *s) 
    {
        /* ... */
    }
  3. Quote:
    ...I decided to achieve it with the se of malloc() and a struct specifier.
    The problem you may be beginning to surmise is that defining all sizes within a file before compilation has its limitations. The purpose of the malloc() family of functions is to allocate memory at runtime. In other words, computation can take place at runtime dependent upon other runtime conditions to allocate the amount of memory needed for a specific situation. No more "one size fits all".

    Having said that, all calls to malloc()or its relatives...) need to ultimately have a corresponding call to free() later in the execution path. Doing so separates newbies from the more experienced. It may not be apparent why this is important, so let me give you a real-world example.

    A company in Silicon Valley about ten years ago was writing a database for a sole customer. The code was being ported from an ancient language only used by this company to C, so the culture didn't have a lot of experience in identifying pitfalls of C programming. In the early phases of development, the database would run fine for a week & then crash. The problem was that memory was being allowed at runtime but never released. Such "memory leaks" consumed all remaining application space, & it was very difficult for that staff to chase down the execution flow in order to find out where memory could (& should...) be deallocated.
    Learning how to use free() now will only help you in the long run.
Reply With Quote