Функция C для заполнения массива строками из пользовательского ввода

#arrays #c #function

#массивы #c #функция

Вопрос:

Я застрял на задании программирования в C. Пользователь должен ввести число, определяющее размер массива, не превышающий 10 элементов, в котором будут храниться имена учащихся. Это должно быть сделано в отдельной от основной функции функции с именем GetNames . Каждое имя может содержать до 14 символов, и GetNames должны вызываться из функции main . Вот мой код:

 #include <stdio.h> 

void getNames(char *a, int n){
    int i;
    for(i=0; i<n; i  ){
        printf("Enter a name: ");
        scanf("%s", amp;a[i]);
    } 

}

void printNames(char *a, int n){
    int i;

    for(i=0; i<n; i  ){
        printf("%sn", amp;a[i]);
    }
}

void main(){
    int num; //number of names in array 'names'
    printf("Num of students: ");
    scanf("%d", amp;num);

    char names[num][15]; //each name is 14 characters plus
                         //a null character
    getNames(names[num], num);
    printNames(names[num], num);

}
  

Код компилируется и выполняется без синтаксических ошибок, но массив заполняется неправильно. Например:

 Num of students: 5
Enter a name: Jeb
Enter a name: Bob
Enter a name: Bill
Enter a name: Val
Enter a name: Matt
  

ВОЗВРАТ:

 JBBVMatt
BBVMatt
BVMatt
VMatt
Matt
  

Очевидно, что существует проблема с записью в массив, но я не уверен, что это такое.

Для этого задания наш профессор был непреклонен в том, что мы не можем использовать какие-либо глобальные переменные. Его формулировка была довольно расплывчатой о том, как мы должны это реализовать. Моей первой мыслью было бы переместить цикл for в GetNames в основную функцию и просто повторно вызывать GetNames, но я хотел бы решение, которое включает это в GetNames. Я новичок в C, в основном занимался Java, поэтому, пожалуйста, потерпите меня. Любая помощь будет оценена.

Ответ №1:

Если опубликованный вами код в точности соответствует используемому вами коду, то он вызывает неопределенное поведение путем доступа к ячейке памяти, которой ваша программа не владеет : getNames(names[num], num); .
Индексация массива в C идет от 0 до n-1 . (или из names[0] names[num-1] ) То же самое в других подобных вызовах.

следующая проблема — прототипы функций для размещения;

 char names[num][15];  
  

Функции необходимо отправить адрес массива массивов. См. Правки в коде, чтобы показать разницу.

Следующей проблемой являются следующие операторы, см. Комментарии после каждого

 getNames(names[num], num);//names[n] points to memory beyond what is owned.
                          //should point to address of beginning of memory amp;names[0]
printNames(names[num], num);//ditto
  

Пример рабочего кода, см. правки для объяснения:

 //void getNames(char *a, int n){//change *a to either a[][15] or (*a)
void getNames(char a[][15], int n){
    int i;
    for(i=0; i<n; i  ){
        printf("Enter a name: ");
        scanf("%s", a[i]);
    } 

}

 //void printNames(char *a, int n){ //change *a to either a[][15] or (*a)
 void printNames(char a[][15], int n){
    int i;

    for(i=0; i<n; i  ){
        printf("%sn", a[i]);
    }
}

void main(){
    int num; //number of names in array 'names'
    printf("Num of students: ");
    scanf("%d", amp;num);

    char names[num][15]; //each name is 14 characters plus
                         //a null character
    //getNames(names[num], num);//names[n] points to memory beyond what is owned.
    //printNames(names[num], num);//ditto
    getNames(amp;names[0], num);
    printNames(amp;names[0], num);

}
  

Комментарии:

1. Спасибо, добрый незнакомец! Для меня это сработало нормально. Я действительно ценю ввод. Мы еще даже не рассмотрели выделение памяти, поэтому это задание похоже на то, что я нахожусь в пещере без фонарика, пытаясь нащупать свой путь.

2. Я бы поменял a местами и n в параметрах, тогда вы могли бы написать (при условии современного компилятора) void getNames(int n, char a[n][15]) { .... } , что может быть легче понять новичку.

3. @HAL9000 — Поскольку нет гарантии , что аргументы функции распознаются в каком-либо определенном порядке, он не определен. например, если char a[n][15] бы они были замечены при вызове getNames before int n , тогда n было бы undefined . Но в противном случае это было бы хорошей идеей. Спасибо

4. Да, порядок вычисления параметров перед вызовом функции не определен, но как только функция вызывается, все значения параметров определяются. И современный c (AFAIK) позволяет использовать целочисленный аргумент в параметре функции в качестве размера массива в другом, но параметр size должен предшествовать параметру array .

5. Некоторое дополнительное объяснение: в getNames(int n, char a[n][15]) этих требованиях нет ничего, что n было вычислено ранее a a , если на него не ссылаются до того, как n оно существует. И это не происходит раньше внутри функции, где оба n и a гарантированно существуют.

Ответ №2:

вы можете сделать следующее

  1. Метод

в main вызове функции, как показано ниже

 getNames(names, num);
printNames(names, num);
  

и измените функции, как показано ниже

 void getNames(char (*a)[15], int n) 
{
   ...
}

void printNames(char (*a)[15], int n)
{
   ...
}
  
  1. Метод, в основных вызовах остается неизменным

void getNames(char a[5][15], int n)

и

void printNames(char a[5][15], int n)

Но вместо использования жестких значений лучше использовать #define размеры строк и столбцов