Skip to main content
added 13 characters in body
Source Link
Deduplicator
  • 19.9k
  • 1
  • 32
  • 65
  1. Don't comment the obvious.

    Because, you know, it's obvious. People expect something unexpected or tricky there, and it's a letdown when they see that you just wasted their time and concentration.

    The greatest danger though is that those useless comments could get out-of-sync with the code, leading to lots of confusion and even more lost time.

  2. The API-documentation belongs to the declaration in the header, not the definition, so users find it without digging in the details.

  3. Consider splitting your code into the public header, the list-implementation, and the test-program. Copy-and-paste is a bad method for reuse.

  4. Don't cast the result of malloc(). And avoid using sizeof(type).
    Both are error-prone and violate DRY. See: Do I cast the result of malloc?

  5. Consider using a flexible-array-member (C99) forin your struct Node for the string. It allows you to save space or store larger strings without extra allocation.

     typedef struct Node {
         struct Node* next;
         int key;
         char string[];
      } Node;
    
  6. insert_end() will try to modify the non-existent last node if the list was empty. That's somewhat sub-optimal.

    Use a double-pointer or special-case it.

  7. remove_beginning() reads the freed ex-node's memory to find the new first node. That's a bit tardy. Read first, then free.

    It also fails to update the last-pointer if the list is now empty.

  8. Why does print_list() fail to print an empty list?

  9. free_list() also commits use-after-free, and its two local variables duplicate each other.

  10. Interesting, why does get_string() ignore the key if the list is exactly one element long?

  11. You are generally ignoring allocation-failure. Whether you abort the program or whatever, handle it!

  12. Consider directing your debug-output to stderr. And only writing it if NDEBUG is not defined.

    Using C99 variadic macros:

     #ifndef NDEBUG
         #define DPRINT(...) (void)fprintf(stderr, __VA_ARGS__)
     #else
         #define DPRINT(...) (void)0
     #endif
    

    Used like:

     DPRINT("My debug message: %s", somestring);
    
  13. If you really want to explicitly return from main() using a preprocessor-constant, use the dedicated EXIT_SUCCESS from <stdlib.h>.
    Of course, return 0; is implicit for main() since C99...

  1. Don't comment the obvious.

    Because, you know, it's obvious. People expect something unexpected or tricky there, and it's a letdown when they see that you just wasted their time and concentration.

    The greatest danger though is that those useless comments could get out-of-sync with the code, leading to lots of confusion and even more lost time.

  2. The API-documentation belongs to the declaration in the header, not the definition, so users find it without digging in the details.

  3. Consider splitting your code into the public header, the list-implementation, and the test-program. Copy-and-paste is a bad method for reuse.

  4. Don't cast the result of malloc(). And avoid using sizeof(type).
    Both are error-prone and violate DRY. See: Do I cast the result of malloc?

  5. Consider using a flexible-array-member (C99) for your struct Node. It allows you to save space or store larger strings without extra allocation.

     typedef struct Node {
         struct Node* next;
         int key;
         char string[];
      } Node;
    
  6. insert_end() will try to modify the non-existent last node if the list was empty. That's somewhat sub-optimal.

    Use a double-pointer or special-case it.

  7. remove_beginning() reads the freed ex-node's memory to find the new first node. That's a bit tardy. Read first, then free.

    It also fails to update the last-pointer if the list is now empty.

  8. Why does print_list() fail to print an empty list?

  9. free_list() also commits use-after-free, and its two local variables duplicate each other.

  10. Interesting, why does get_string() ignore the key if the list is exactly one element long?

  11. You are generally ignoring allocation-failure. Whether you abort the program or whatever, handle it!

  12. Consider directing your debug-output to stderr. And only writing it if NDEBUG is not defined.

    Using C99 variadic macros:

     #ifndef NDEBUG
         #define DPRINT(...) (void)fprintf(stderr, __VA_ARGS__)
     #else
         #define DPRINT(...) (void)0
     #endif
    

    Used like:

     DPRINT("My debug message: %s", somestring);
    
  13. If you really want to explicitly return from main() using a preprocessor-constant, use the dedicated EXIT_SUCCESS from <stdlib.h>.
    Of course, return 0; is implicit for main() since C99...

  1. Don't comment the obvious.

    Because, you know, it's obvious. People expect something unexpected or tricky there, and it's a letdown when they see that you just wasted their time and concentration.

    The greatest danger though is that those useless comments could get out-of-sync with the code, leading to lots of confusion and even more lost time.

  2. The API-documentation belongs to the declaration in the header, not the definition, so users find it without digging in the details.

  3. Consider splitting your code into the public header, the list-implementation, and the test-program. Copy-and-paste is a bad method for reuse.

  4. Don't cast the result of malloc(). And avoid using sizeof(type).
    Both are error-prone and violate DRY. See: Do I cast the result of malloc?

  5. Consider using a flexible-array-member (C99) in your struct Node for the string. It allows you to save space or store larger strings without extra allocation.

     typedef struct Node {
         struct Node* next;
         int key;
         char string[];
     } Node;
    
  6. insert_end() will try to modify the non-existent last node if the list was empty. That's somewhat sub-optimal.

    Use a double-pointer or special-case it.

  7. remove_beginning() reads the freed ex-node's memory to find the new first node. That's a bit tardy. Read first, then free.

    It also fails to update the last-pointer if the list is now empty.

  8. Why does print_list() fail to print an empty list?

  9. free_list() also commits use-after-free, and its two local variables duplicate each other.

  10. Interesting, why does get_string() ignore the key if the list is exactly one element long?

  11. You are generally ignoring allocation-failure. Whether you abort the program or whatever, handle it!

  12. Consider directing your debug-output to stderr. And only writing it if NDEBUG is not defined.

    Using C99 variadic macros:

     #ifndef NDEBUG
         #define DPRINT(...) (void)fprintf(stderr, __VA_ARGS__)
     #else
         #define DPRINT(...) (void)0
     #endif
    

    Used like:

     DPRINT("My debug message: %s", somestring);
    
  13. If you really want to explicitly return from main() using a preprocessor-constant, use the dedicated EXIT_SUCCESS from <stdlib.h>.
    Of course, return 0; is implicit for main() since C99...

added 1 character in body
Source Link
Deduplicator
  • 19.9k
  • 1
  • 32
  • 65
  1. Don't comment the obvious.

    Because, you know, it's obvious. People expect something unexpected or tricky there, and it's a letdown when they see that you just wasted their time and concentration.

    The greatest danger though is that those useless comments could get out-of-sync with the code, leading to lots of confusion and even more lost time.

  2. The API-documentation belongs to the declaration in the header, not the definition, so users find it without digging in the details.

  3. Consider splitting your code into the public header, the list-implementation, and the test-program. Copy-and-patepaste is a bad method for reuse.

  4. Don't cast the result of malloc(). And avoid using sizeof(type).
    Both are error-prone and violate DRY. See: Do I cast the result of malloc?

  5. Consider using a flexible-array-member (C99) for your struct Node. It allows you to save space or store larger strings without extra allocation.

     typedef struct Node {
         struct Node* next;
         int key;
         char string[];
      } Node;
    
  6. insert_end() will try to modify the non-existent last node if the list was empty. That's somewhat sub-optimal.

    Use a double-pointer or special-case it.

  7. remove_beginning() reads the freed ex-node's memory to find the new first node. That's a bit tardy. Read first, then free.

    It also fails to update the last-pointer if the list is now empty.

  8. Why does print_list() fail to print an empty list?

  9. free_list() also commits use-after-free, and its two local variables duplicate each other.

  10. Interesting, why does get_string() ignore the key if the list is exactly one element long?

  11. You are generally ignoring allocation-failure. Whether you abort the program or whatever, handle it!

  12. Consider directing your debug-output to stderr. And only writing it if NDEBUG is not defined.

    Using C99 variadic macros:

     #ifndef NDEBUG
         #define DPRINT(...) (void)fprintf(stderr, __VA_ARGS__)
     #else
         #define DPRINT(...) (void)0
     #endif
    

    Used like:

     DPRINT("My debug message: %s", somestring);
    
  13. If you really want to explicitly return from main() using a preprocessor-constant, use the dedicated EXIT_SUCCESS from <stdlib.h>.
    Of course, return 0; is implicit for main() since C99...

  1. Don't comment the obvious.

    Because, you know, it's obvious. People expect something unexpected or tricky there, and it's a letdown when they see that you just wasted their time and concentration.

    The greatest danger though is that those useless comments could get out-of-sync with the code, leading to lots of confusion and even more lost time.

  2. The API-documentation belongs to the declaration in the header, not the definition, so users find it without digging in the details.

  3. Consider splitting your code into the public header, the list-implementation, and the test-program. Copy-and-pate is a bad method for reuse.

  4. Don't cast the result of malloc(). And avoid using sizeof(type).
    Both are error-prone and violate DRY. See: Do I cast the result of malloc?

  5. Consider using a flexible-array-member (C99) for your struct Node. It allows you to save space or store larger strings without extra allocation.

     typedef struct Node {
         struct Node* next;
         int key;
         char string[];
      } Node;
    
  6. insert_end() will try to modify the non-existent last node if the list was empty. That's somewhat sub-optimal.

    Use a double-pointer or special-case it.

  7. remove_beginning() reads the freed ex-node's memory to find the new first node. That's a bit tardy. Read first, then free.

    It also fails to update the last-pointer if the list is now empty.

  8. Why does print_list() fail to print an empty list?

  9. free_list() also commits use-after-free, and its two local variables duplicate each other.

  10. Interesting, why does get_string() ignore the key if the list is exactly one element long?

  11. You are generally ignoring allocation-failure. Whether you abort the program or whatever, handle it!

  12. Consider directing your debug-output to stderr. And only writing it if NDEBUG is not defined.

    Using C99 variadic macros:

     #ifndef NDEBUG
         #define DPRINT(...) (void)fprintf(stderr, __VA_ARGS__)
     #else
         #define DPRINT(...) (void)0
     #endif
    

    Used like:

     DPRINT("My debug message: %s", somestring);
    
  13. If you really want to explicitly return from main() using a preprocessor-constant, use the dedicated EXIT_SUCCESS from <stdlib.h>.
    Of course, return 0; is implicit for main() since C99...

  1. Don't comment the obvious.

    Because, you know, it's obvious. People expect something unexpected or tricky there, and it's a letdown when they see that you just wasted their time and concentration.

    The greatest danger though is that those useless comments could get out-of-sync with the code, leading to lots of confusion and even more lost time.

  2. The API-documentation belongs to the declaration in the header, not the definition, so users find it without digging in the details.

  3. Consider splitting your code into the public header, the list-implementation, and the test-program. Copy-and-paste is a bad method for reuse.

  4. Don't cast the result of malloc(). And avoid using sizeof(type).
    Both are error-prone and violate DRY. See: Do I cast the result of malloc?

  5. Consider using a flexible-array-member (C99) for your struct Node. It allows you to save space or store larger strings without extra allocation.

     typedef struct Node {
         struct Node* next;
         int key;
         char string[];
      } Node;
    
  6. insert_end() will try to modify the non-existent last node if the list was empty. That's somewhat sub-optimal.

    Use a double-pointer or special-case it.

  7. remove_beginning() reads the freed ex-node's memory to find the new first node. That's a bit tardy. Read first, then free.

    It also fails to update the last-pointer if the list is now empty.

  8. Why does print_list() fail to print an empty list?

  9. free_list() also commits use-after-free, and its two local variables duplicate each other.

  10. Interesting, why does get_string() ignore the key if the list is exactly one element long?

  11. You are generally ignoring allocation-failure. Whether you abort the program or whatever, handle it!

  12. Consider directing your debug-output to stderr. And only writing it if NDEBUG is not defined.

    Using C99 variadic macros:

     #ifndef NDEBUG
         #define DPRINT(...) (void)fprintf(stderr, __VA_ARGS__)
     #else
         #define DPRINT(...) (void)0
     #endif
    

    Used like:

     DPRINT("My debug message: %s", somestring);
    
  13. If you really want to explicitly return from main() using a preprocessor-constant, use the dedicated EXIT_SUCCESS from <stdlib.h>.
    Of course, return 0; is implicit for main() since C99...

added 156 characters in body
Source Link
Deduplicator
  • 19.9k
  • 1
  • 32
  • 65
  1. Don't comment the obvious.

    Because, you know, it's obvious. People expect something unexpected or tricky there, and it's a letdown when they see that you just wasted their time and concentration.

    The greatest danger though is that those useless comments could get out-of-sync with the code, leading to lots of confusion and even more lost time.

  2. The API-documentation belongs to the declaration in the header, not the definition, so users find it without digging in the details.

  3. Consider splitting your code into the public header, the list-implementation, and the test-program. Copy-and-pate is a bad method for reuse.

  4. Don't cast the result of malloc(). And avoid using sizeof(type).
    Both are error-prone and violate DRY. See: Do I cast the result of malloc?

  5. Consider using a flexible-array-member (C99) for your struct Node. It allows you to save space or store larger strings without extra allocation.

     typedef struct Node {
         struct Node* next;
         int key;
         char string[];
      } Node;
    
  6. insert_end() will try to modify the non-existent last node if the list was empty. That's somewhat sub-optimal.

    Use a double-pointer or special-case it.

  7. remove_beginning() reads the freed ex-node's memory to find the new first node. That's a bit tardy. Read first, then free.

    It also fails to update the last-pointer if the list is now empty.

  8. Why does print_list() fail to print an empty list?

  9. free_list() also commits use-after-free, and its two local variables duplicate each other.

  10. Interesting, why does get_string() ignore the key if the list is exactly one element long?

  11. You are generally ignoring allocation-failure. Whether you abort the program or whatever, handle it!

  12. Consider directing your debug-output to stderr. And only writing it if NDEBUG is not defined.

    Using C99 variadic macros:

     #ifndef NDEBUG
         #define DPRINT(...) (void)fprintf(stderr, __VA_ARGS__)
     #else
         #define DPRINT(...) (void)0
     #endif
    

    Used like:

     DPRINT("My debug message: %s", somestring);
    
  13. If you really want to explicitly return from main() using a preprocessor-constant, use the dedicated EXIT_SUCCESS from <stdlib.h>.
    Of course, return 0; is implicit for main() since C99...

  1. Don't comment the obvious.

    Because, you know, it's obvious. People expect something unexpected or tricky there, and it's a letdown when they see that you just wasted their time and concentration.

  2. The API-documentation belongs to the declaration in the header, not the definition, so users find it without digging in the details.

  3. Consider splitting your code into the public header, the list-implementation, and the test-program. Copy-and-pate is a bad method for reuse.

  4. Don't cast the result of malloc(). And avoid using sizeof(type).
    Both are error-prone and violate DRY. See: Do I cast the result of malloc?

  5. Consider using a flexible-array-member (C99) for your struct Node. It allows you to save space or store larger strings without extra allocation.

     typedef struct Node {
         struct Node* next;
         int key;
         char string[];
      } Node;
    
  6. insert_end() will try to modify the non-existent last node if the list was empty. That's somewhat sub-optimal.

    Use a double-pointer or special-case it.

  7. remove_beginning() reads the freed ex-node's memory to find the new first node. That's a bit tardy. Read first, then free.

    It also fails to update the last-pointer if the list is now empty.

  8. Why does print_list() fail to print an empty list?

  9. free_list() also commits use-after-free, and its two local variables duplicate each other.

  10. Interesting, why does get_string() ignore the key if the list is exactly one element long?

  11. You are generally ignoring allocation-failure. Whether you abort the program or whatever, handle it!

  12. Consider directing your debug-output to stderr. And only writing it if NDEBUG is not defined.

    Using C99 variadic macros:

     #ifndef NDEBUG
         #define DPRINT(...) (void)fprintf(stderr, __VA_ARGS__)
     #else
         #define DPRINT(...) (void)0
     #endif
    

    Used like:

     DPRINT("My debug message: %s", somestring);
    
  13. If you really want to explicitly return from main() using a preprocessor-constant, use the dedicated EXIT_SUCCESS from <stdlib.h>.
    Of course, return 0; is implicit for main() since C99...

  1. Don't comment the obvious.

    Because, you know, it's obvious. People expect something unexpected or tricky there, and it's a letdown when they see that you just wasted their time and concentration.

    The greatest danger though is that those useless comments could get out-of-sync with the code, leading to lots of confusion and even more lost time.

  2. The API-documentation belongs to the declaration in the header, not the definition, so users find it without digging in the details.

  3. Consider splitting your code into the public header, the list-implementation, and the test-program. Copy-and-pate is a bad method for reuse.

  4. Don't cast the result of malloc(). And avoid using sizeof(type).
    Both are error-prone and violate DRY. See: Do I cast the result of malloc?

  5. Consider using a flexible-array-member (C99) for your struct Node. It allows you to save space or store larger strings without extra allocation.

     typedef struct Node {
         struct Node* next;
         int key;
         char string[];
      } Node;
    
  6. insert_end() will try to modify the non-existent last node if the list was empty. That's somewhat sub-optimal.

    Use a double-pointer or special-case it.

  7. remove_beginning() reads the freed ex-node's memory to find the new first node. That's a bit tardy. Read first, then free.

    It also fails to update the last-pointer if the list is now empty.

  8. Why does print_list() fail to print an empty list?

  9. free_list() also commits use-after-free, and its two local variables duplicate each other.

  10. Interesting, why does get_string() ignore the key if the list is exactly one element long?

  11. You are generally ignoring allocation-failure. Whether you abort the program or whatever, handle it!

  12. Consider directing your debug-output to stderr. And only writing it if NDEBUG is not defined.

    Using C99 variadic macros:

     #ifndef NDEBUG
         #define DPRINT(...) (void)fprintf(stderr, __VA_ARGS__)
     #else
         #define DPRINT(...) (void)0
     #endif
    

    Used like:

     DPRINT("My debug message: %s", somestring);
    
  13. If you really want to explicitly return from main() using a preprocessor-constant, use the dedicated EXIT_SUCCESS from <stdlib.h>.
    Of course, return 0; is implicit for main() since C99...

added 1 character in body
Source Link
Deduplicator
  • 19.9k
  • 1
  • 32
  • 65
Loading
fixed minor typos
Source Link
Edward
  • 67.2k
  • 4
  • 120
  • 284
Loading
Source Link
Deduplicator
  • 19.9k
  • 1
  • 32
  • 65
Loading