#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
beforeint n
, тогдаn
было бы undefined . Но в противном случае это было бы хорошей идеей. Спасибо4. Да, порядок вычисления параметров перед вызовом функции не определен, но как только функция вызывается, все значения параметров определяются. И современный c (AFAIK) позволяет использовать целочисленный аргумент в параметре функции в качестве размера массива в другом, но параметр size должен предшествовать параметру array .
5. Некоторое дополнительное объяснение: в
getNames(int n, char a[n][15])
этих требованиях нет ничего, чтоn
было вычислено ранееa
a
, если на него не ссылаются до того, какn
оно существует. И это не происходит раньше внутри функции, где обаn
иa
гарантированно существуют.
Ответ №2:
вы можете сделать следующее
- Метод
в main
вызове функции, как показано ниже
getNames(names, num);
printNames(names, num);
и измените функции, как показано ниже
void getNames(char (*a)[15], int n)
{
...
}
void printNames(char (*a)[15], int n)
{
...
}
- Метод, в основных вызовах остается неизменным
void getNames(char a[5][15], int n)
и
void printNames(char a[5][15], int n)
Но вместо использования жестких значений лучше использовать #define
размеры строк и столбцов