c - 修改 C 电话簿程序以返回匹配数组,而不仅仅是单个匹配

标签 c arrays

我正在修改一个小程序,我已经成功地将这个小程序变成了一个更大的程序,但是我仍然需要两个功能。

  1. 有编辑选项
  2. 搜索时返回多条记录。

我正在帮助我的一个 friend 。

#include <stdio.h>


#define CAPACITY 100

/* User commands */

#define ADD 'a'
#define FIND   'f'
#define LIST   'l'
#define QUIT   'q'

#define NAME_LEN 80
#define NUMBER_LEN 40

/* In memory representation of an entry in the phonebook. */

typedef struct {
  char name[ NAME_LEN ];
  char number[ NUMBER_LEN ];
} phone_record;

/* Procedures in phonebook.c */

char get_command( void );
phone_record *get_record( void );
void add_record( phone_record *new_record );
void list_phonebook( void );
int find_name( char *name );

int num_entries;           // Number of entries currently in the phone book
phone_record **phonebook;  // Where the names are stored

int main( int argc, char **argv ) {
  char ch;
  char name[ NAME_LEN ];
  char confirm[ 10 ];
  phone_record *rec;
  int loc;

  // Create an empty phonebook
  phonebook = (phone_record **)malloc( sizeof( phone_record *) * CAPACITY );
  num_entries = 0;

  // Read commands until the user gets tired
  while ( ( ch = get_command() ) != QUIT ) {
    switch( ch ) {
      case ADD:
        // Get new info
        rec = get_record();

          add_record( rec );

        break;

      case FIND:
        // Name to find
        printf( "Name:  " );
        scanf( "%s", name );

        // Look for the name
        if ( ( loc = find_name( name ) ) != -1 ) {
          printf( "Number:  %s\n", phonebook[ loc ]->number );
        }
        else {
          printf( "That name is not in the phonebook\n" );
        }
        break;

      case LIST:
        // List the phonebook
        list_phonebook();
        break;
    }
  }
}

/* 
 * Read and return a command from the keyboard. 
 */
char get_command() {
  char line[ 80 ];

  do {
    // Get input
    printf( "pb> " );

    // scanf returns -1 when it encoutners EOF - pretend we saw quit
    if ( scanf( "%s", line ) == -1 ) {
      line[ 0 ] = QUIT;
      printf( "\n" );  // Add new line so terminal looks nice
    }

    // Verify input (lightly)
    switch( line[ 0 ] ) {
      case ADD:
      case FIND:
      case LIST:
      case QUIT:
        break;
      default:
        printf( "Unrecognized command\n" );
        line[ 0 ] = 0;
    }
  } while ( line[ 0 ] == 0 );

  return line[ 0 ];
}

/*
 * Add a new record to the phonebook.
 */
void add_record( phone_record *new_record ) {
  int cur;

  // Make sure there is room
  if ( num_entries == CAPACITY ) {
    printf( "Sorry phonebook is full\n" );
  }
  else {
    // Insertion sort.  Start at bottom and copy elements down one until
    // you find the first one less than what we are adding or we hit the
    // top of the phonebook
    for ( cur = num_entries; 
          cur > 0 && strcmp( phonebook[ cur - 1 ]->name, new_record->name ) > 0;
          cur = cur - 1 ) {

      phonebook[ cur ] = phonebook[ cur - 1 ];
    }

    // Add the entry in the open slot
    phonebook[ cur ] = new_record;
    num_entries = num_entries + 1;
  }
}

/*
 * List the entries in the phonebook.
 */
void list_phonebook() {
  int i;

  if ( num_entries != 0 ) {
    printf( "Name\t\tNumber\n" );
    printf( "----\t\t------\n" );

    for ( i = 0; i < num_entries; i = i + 1 ) {
      printf( "%s\t\t%s\n", phonebook[ i ]->name, phonebook[ i ]->number );
    }
  }
  else {
    printf( "There are no entries in the phonebook\n" );
  }
}


/*
 * Find a name in the phonebook.  -1 means it is not there.
 */
int find_name( char *name ) {
  int pos = -1;
  int i;

  for ( i = 0; pos == -1 && i < num_entries; i = i + 1 ) {
    if ( strcmp( name, phonebook[ i ]->name ) == 0 ) pos = i;
  }  

  return pos;
}

/*
 * Read and return a phone record from the keyboard.
 */
phone_record *get_record() {
  phone_record *rec;
  char *name;
  char *number;

  // Allocate storage for the phone record.  Since we want the record
  // to live after the function returns we need to use malloc
  rec = (phone_record *)malloc( sizeof( phone_record ) );

  // Get the data
  printf( "Name:  " );
  scanf( "%s", rec->name );

  printf( "Phone:  " );
  scanf( "%s", rec->number );

  return rec;
}

在电话簿数组中查找匹配名称的 find_name() 函数是:

int find_name( char *name ) {
  int pos = -1;
  int i;

  for ( i = 0; pos == -1 && i < num_entries; i = i + 1 ) {
    if ( strcmp( name, phonebook[ i ]->name ) == 0 ) pos = i;
  }  

  return pos;
}

它只返回一个整数,显示电话簿中匹配元素的位置:

if ( ( loc = find_name( name ) ) != -1 ) {
  printf( "Number:  %s\n", phonebook[ loc ]->number );
}

我认为 find_name 方法应该返回一个数组,但我不知道如何实现。

最佳答案

使用负数 (-1) 来指示整数列表的结尾可能是最简单的返回整数数组的方法。

因此您的函数将被修改为如下所示。我实际上尚未编译此文件,因此您可能需要修复一些问题。

int find_name( char *name, int *iList, int nListSize ) {
  int pos = -1;
  int i;
  int j;

  for ( j = i = 0; i < num_entries; i = i + 1 ) {
    if ( strcmp( name, phonebook[ i ]->name ) == 0 ) {
        if (j + 1 < nListSize)
            iList[j++] = i;
    }
  }  

  iList[j] = -1;      // indicate the end of the list
  if (j < nListSize) pos = j;  // return the number of items in the list
  return pos;
}

您将需要修改使用此函数的方式来创建整数数组并传递该数组以及最大数组条目数。然后检查返回值以确定找到了多少个匹配项(如果有)。

如果发现的匹配项数量多于可用于放入的数组元素,则该函数将返回 -1。

编辑

case FIND: 中,您将执行如下所示的输出循环。同样,我还没有进行编译或测试,但这就是概念。如果此示例中有超过 100 个匹配名称,那么您确实会遇到问题,因此您需要考虑如何处理这种可能性:

// Look for the name
{
    int   aList[100];   // just a large array and hope no more than this matching entries
    if ( ( loc = find_name( name, aList, 100 ) ) > 0 ) {
        int iLoop = 0;
        // loop through the list to print out the matching entries.
        for (iLoop= 0; aList[iLoop] >= 0; iLoop++) {
            printf( "Number:  %s\n", phonebook[ aList[iLoop] ]->number );
        }
    }
    else {
        printf( "That name is not in the phonebook or too many matches\n" );
    }
}

编辑

您还可以考虑采用稍微不同的查找方法来创建使用迭代器类型方法的 find_name()。这个想法是有一个变量充当电话簿的迭代器。如果存在匹配的名称,则迭代器变量返回指向匹配数据的指针。

我还没有编译或测试这个,因此可能需要您做一些工作。

由于迭代器结构需要更新,因此我们需要传递一个指向迭代器结构的指针,以便在处理电话簿数组时可以更新它。

int find_name( char *name, phonebookitera *pItera ) {
  int pos = -1;

  for (; pItera->pos < num_entries; pItera->pos++ ) {
    if ( strcmp( name, phonebook[ pItera->pos ]->name ) == 0 ) {
        // copy the matching pointers to our iterator 
        pItera->name = phonebook[ pItera->pos ]->name;
        pItera->number = phonebook[ pItera->pos ]->number;
        // we will return the matching position in phonebook though not necessary
        pos = pItera->pos;
        pItera->pos++;     // increment to the following element
        return pos;
    }
  }  

  return pos;
}

这个函数将在类似下面的代码中使用。

{
    phonebookitera myItera = {0};
    // iterate through the list to print out the matching entries.
    if (find_name (name, &myItera) >= 0) {
        do {
            printf( "Number:  %s\n", myItera.number );
        } while (find_name (name, &myItera) >= 0);
    } else {
        printf( "That name is not in the phonebook\n" );
    }

}

您可以将 phonebookitera 定义为:

typedef struct {
    int  pos;
    char *name;
    char *number;
} phonebookitera;

关于c - 修改 C 电话簿程序以返回匹配数组,而不仅仅是单个匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26217535/

相关文章:

android - 如何在android studio中查看数组的内容

Java错误: Bad Operand Type for binary operator <

javascript - 创建小时数组 : 00:00, 01 :00, 02:00

c - 暂停程序执行直到处理中断 - 如何实现?

c - 移动字符串数组中的元素,C

java - 将值添加到 JSONArray 时如何保持值的顺序?

javascript - 在子函数中使用带有闭包的 concat 方法

c - Linux:从蓝牙 LE 接收数据

c - 对于大型和小型 btree,btree 中每个节点的键数平均相同吗?

c - 如何在 linux C 中获得接口(interface)的最大带宽?