-2
int main() {

  int n, found, query_no = 0;
  unsigned long int *phone;

  char **str, query[30], c;

  scanf("%d", &n);

  str = (char**) malloc(sizeof(char*) * n); //creating a pointer array of strings

  phone = (unsigned long int*) malloc(sizeof(unsigned long int) * n);
  for (int i = 0; i < n; i++) {
    str[i] = (char*) malloc(sizeof(char) * 30); //iitializing each pointer in arry
  }
  for (int i = 0; i < n; i++) {
    scanf("%s", *(str + i));
    scanf("%u", phone + i);
  }

  gets(query);
  char *p;
  p = query;

  while (*(p = gets(query)) != '\0')  //checks if blank line is entered
  {
    found = 0;
    for (int j = 0; j < n; j++) {
      /*two pointers are being passed here,*/
      /* one to the line entered and       */
      /* other to each character array pointed to by the pointer array*/
      if (strcmp(p, *(str + j)) == 0) {
        printf("%s", *(str + j));
        printf("=");
        printf("%u", *(phone + j));
        found = 1;
        break;
      }
    }
    if (found == 0) //if record not found, print so
      printf("Not found");
    printf("\n");
  }

The code inputs a phone book from user by first inputting the number of records to be inserted then in each new line a record is entered in the form of name number. Then the user searches for an unknown number records and we print the name and number if the records is found otherwise we print not found.

Source : Hackerrank 30 days of code Day 8 (I hope I am not violating any rules here, please tell me if I am)

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
Harshita
  • 23
  • 6
  • 2
    Undefined behaviour. – ThingyWotsit Jun 06 '17 at 14:06
  • 1
    [Please see this discussion on why not to cast the return value of malloc() and family in C..](https://stackoverflow.com/q/605845/2173917) – Sourav Ghosh Jun 06 '17 at 14:07
  • Please ___properly___ indent your code. Machine (Compiler) can read and compile anything, but for humans, it needs to make a little _sense_ while reading a block of text as _code_. :) – Sourav Ghosh Jun 06 '17 at 14:07
  • You're probably reading/writing memory you're not supposed to. Run your code through [valgrind](http://valgrind.org) with various inputs and it should tell you where. – dbush Jun 06 '17 at 14:10
  • 1
    gets() ..... :(( – ThingyWotsit Jun 06 '17 at 14:10
  • Showing the _exact_ input would help. I have doubt `gets(query);` is working as expected. Add `query[0] = 0;` before the `gets()`. – chux - Reinstate Monica Jun 06 '17 at 15:07
  • Suppose the phone number begins with a `0` as they do in my country? – Weather Vane Jun 06 '17 at 15:10
  • `while (*(p = gets(query)) != '\0')` generates a compiler warning " 'char *' differs in levels of indirection from 'int' ". – Weather Vane Jun 06 '17 at 15:15
  • @WeatherVane umm.. yes, I kept looking at that, over and over... – ThingyWotsit Jun 06 '17 at 17:02
  • @ThingyWotsit I looked again, and the reason is that MSVC no longer includes `gets` in the library headers, but it is still in the library itself. Without a function prototype, the compiler assumes its return value is `int`, and the part objected to is `p = gets(query)`. – Weather Vane Jun 06 '17 at 17:18
  • `scanf("%u", phone + i);` --> `scanf("%lu", phone + i);` – BLUEPIXY Jun 06 '17 at 22:50
  • `*(p = gets(query))` : `gets` may return `NULL`. – BLUEPIXY Jun 06 '17 at 22:56
  • for ease of readability and understandig: 1) consistently indent the code. indent after every opening brace '{'. Unindent before every closing brace '}'. suggest each indent level be 4 spaces. 2) separate code blocks (for, if, else, while, do...while, switch, case, default) via a single blank line. 3) follow the axiom: *only one statement per line and (at most) one variable declaration per statement.* – user3629249 Jun 07 '17 at 15:08
  • when calling any of the heap allocation functions: 1) do not cast the returned value. Its' type is `void*` so can be assigned to any pointer. Casting just clutters the code, making it much more difficult to understand, debug, etc. 2) always check (!=NULL) the returned value to assure the operation was successful. – user3629249 Jun 07 '17 at 15:11
  • when calling any of the `scanf()` family of functions: 1) always check the returned value (not the parameter value) to assure the operation was successful. 2) when using the '%s' input/format specifier, always include a MAX CHARACTERS modifier that is one less than the length of the input buffer so the input cannot overflow the buffer. Such overflow results in undefined behavior and can lead to a seg fault event. – user3629249 Jun 07 '17 at 15:13
  • please post a link to the actual hankerrank question. However, I suspect that the first read value has an allowed maximum, so can pre-declare the the `array of pointers to char` array and thereby avoid any calls to `malloc()` – user3629249 Jun 07 '17 at 15:18
  • the posted code does not compile. amongst other things, it is missing one or more lines at the end and is missing the statements: `#include ` and `#include ` and `#include ` – user3629249 Jun 07 '17 at 15:25
  • this line: `phone = (unsigned long int*) malloc(sizeof(unsigned long int) * n);` is allocating room for 'n' instances of 'unsigned long int' However, this line: `scanf("%u", phone + i);` is only reading 'unsigned int' – user3629249 Jun 07 '17 at 15:29

1 Answers1

1

the following proposed code:

  1. cleanly compiles
  2. performs the desired function
  3. avoids any use of the heap allocation functions, like malloc()
  4. allows easy modification to the actual MAX value for 'n' via a #define statement.
  5. allows easy modification to the max name length via a #define statement.
  6. consolidates the data representation into a simple struct.
  7. avoids calling functions (I.E. gets()) that has been removed from the C standard.
  8. because it is a 'Hackerrank' item, does not perform error checking.
  9. stops when a blank line is read for a 'query'
  10. note the use of size_t rather than int as the values are never <0

And now the proposed code:

#include <stdio.h>
#include <string.h>

#define MAX_NAMES 500
#define MAX_NAME_LEN 30

struct phoneBook
{
    char name[ MAX_NAME_LEN + 1]; // +1 to allow for NUL terminator
    unsigned long phone;
};

struct phoneBook myPhoneBook[ MAX_NAMES ];

int main( void )
{
    size_t n;

    scanf("%lu", &n);

    for (size_t i = 0; i < n; i++)
    {
        scanf( "%29s", myPhoneBook[i].name );
        char *newline;
        if( NULL != (newline = strchr( myPhoneBook[i].name, '\n' ) ) )
        {
            *newline = '\0';
        }
        scanf( "%lu",  &myPhoneBook[i].phone );
    }


    char query[MAX_NAME_LEN+2]; // +2 to allow for NUL byte and newline

    while ( fgets( query, sizeof(query), stdin ) )
    {
        if( query[0] == '\n' )
            break;

        char *newline;
        if( NULL != (newline = strchr( query, '\n' ) ) )
        {
            *newline = '\0';
        }

        size_t found = 0;

        for ( size_t j = 0; j < n; j++)
        {
            /*two pointers are being passed here,*/
            /* one to the line entered and       */
            /* other to each character array pointed to by the pointer array*/
            if (strcmp( query, myPhoneBook[j].name ) == 0)
            {
                printf( "%s", myPhoneBook[j].name );
                printf( "=" );
                printf( "%lu", myPhoneBook[j].phone );
                found = 1;
                break;
            }
        }

        if ( !found ) //if record not found, print so
            printf("Not found");
        printf("\n");
    }

    return 0;
}

Note: printf() and scanf() are SLOW. Suggest modifying the proposed code to use the following two functions, so never call printf() nor scanf():

void fastRead( size_t *a );
void fastWrite( size_t a );

inline void fastRead(size_t *a)
{
    int c=0;
    // note: 32 is space character
    // consume leading trash
    while (c<33) c=getchar_unlocked();

    // initialize result value
    *a=0;

    // punctuation parens, etc are show stoppers
    while (c>47 && c <58)
    { // then in range 0...9
        *a = (*a)*10 + (size_t)(c-48);
        c=getchar_unlocked();
    }
    //printf( "%s, value: %lu\n", __func__, *a );
} // end function: fastRead


inline void fastWrite(size_t a)
{
    char snum[20];
    //printf( "%s, %lu\n", __func__, a );

    int i=0;
    // decompose 'a' into char array
    do
    {
        // 48 is numeric character 0
        snum[i++] = (char)((a%10)+(size_t)48);
        a=a/10;
    }while(a>0);

    i=i-1; // correction for overincrement from prior 'while' loop

    while(i>=0)
    {
        putchar_unlocked(snum[i--]);
    }
    putchar_unlocked('\n');
} // end function: fastWrite
user3629249
  • 16,402
  • 1
  • 16
  • 17