Инициализировать значение определяемых пользователем параметров для массива в C - PullRequest
0 голосов
/ 13 июля 2020

Я узнал из учебника, что есть только несколько способов инициализировать массив.

Метод первый:

int ary[5] = {1,2,3,4,5};

Метод второй:

int ary[] = {1,2,3,4,5};

Но что, если я хочу ввести в массив значения, определенные пользователем. Подойдет ли этот код? Может ли кто-нибудь научить меня, как это сделать лучше?

#include<stdio.h>
#include<conio.h>

int main()
{
    int i, n;
    printf("Enter array parameter: \n");
    scanf("%d",&n);
    int a[n]; 
    int b[n];
    
    for(i=0;i<n;i++)
    {
        printf("Enter value for array a[%d]: \n",i+1);
        scanf("%d",&a[i]);
    }
    n -= 1; 
    for(i=0;i<=n;i++)
    {
        b[i]=a[n-i];
    }
    printf("Value of array b[] is: \n");
    for(i=0;i<=n;i++)
    {
        printf("%d ",b[i]);
    }
    for(i=0;i<=n;i++)
    {
        printf("\narray b[%d] = %d ",i,b[i]);
    }
    
    getch();
}

введите описание изображения здесь

Ответы [ 5 ]

1 голос
/ 13 июля 2020
int ary[5] {1,2,3,4,5};

Это недопустимая инициализация массива. Это должно быть

int ary[5] = {1,2,3,4,5};

Обратите внимание на знак равенства.

В противном случае инициализация вашего массива действительна для C99 и выше. Обычный c не позволит использовать переменную для инициализации размера массива.

0 голосов
/ 13 июля 2020

«Подойдет ли этот код? Может ли кто-нибудь научить меня, как это сделать лучше?»

Этот код нормален с синтаксической точки зрения (вы исправили неправильную инициализацию), но не переносится, поскольку вы используете массивы переменной длины (VLA), которые могут не поддерживаться какой-либо реализацией (они предоставляются моими расширениями компилятора) и полностью соответствуют стандарту C99.

A лучший способ сделать это - использовать вместо него malloc() и выделить память для массива в куче.

Это также имеет то преимущество, что вы можете изменить размер массива, если хотите (сделайте его больше fe ) и free() память для массива, когда она больше не нужна.

Сопутствующие материалы:

int i, n;

printf("Enter amount of array elements: \n");
if (scanf("%d",&n) != 1)
{ 
    fputs("Error at input!", stderr);
    return EXIT_FAILURE;
}

int* a = malloc ( sizeof(*a) * n );
if (!a)
{ 
    fputs("Error at allocation for a!", stderr);
    return EXIT_FAILURE;
}

int* b = malloc ( sizeof(*b) * n );
if (!b)
{ 
    fputs("Error at allocation for b!", stderr);
    return EXIT_FAILURE;
}

for (i = 0; i < n; i++)
{
    printf("Enter value for array a[%d]: \n", i);
    if (scanf("%d", &a[i]) != 1)
    { 
       fprintf(stderr, "Error at input for a[%d]!", i);
       return EXIT_FAILURE;
    }
}

...

free(a);
free(b);
0 голосов
/ 13 июля 2020

Как кто-то заметил, в C первый способ не работает. Однако это действительный C ++.

Второй способ int ary[] = {1,2,3,4,5}; работает, массив ary инициализируется 5 элементами во время компиляции (еще до того, как вы запустите программу). Память выделяется в стеке.

Вы также можете сделать это так: int ary[6] = {1,2,3,4,5};, где вы указываете, какую длину вы хотите, чтобы массив был. Затем вы можете получить доступ к ary[5] и изменить его на любое значение, которое вы хотите (по умолчанию это 0).

ПРИМЕЧАНИЕ : ary[6] выходит за пределы, поскольку элементы массива go от 0 до 5.

В вашем коде вы используете так называемые массивы переменной длины (VLA), и, как указано в Wikipedia , они выделяются автоматически c продолжительность хранения в стеке. Это означает, что, когда функция, в которой вы их объявили, заканчивается, заканчивается и их срок службы (они являются локальными по отношению к области действия функции, в которой вы их объявляете). Чтобы понять, почему это важно, рассмотрите этот фрагмент кода:

int *func(int n) {
   int v[n]; // variable length array

   v[0] = 1;
   v[1] = 2;
   v[2] = 3;

   return v;   // this will not work, variable length arrays will be destroyed
               // when the function they belong to goes out of scope
}

int main() {
   int *v;
   v = func(3);  // when you will try to access the memory in v, it will be undefined 
                 // behaviour (can seg fault, the memory is not yours anymore)
   // print values in v
   return 0;
}

Чтобы исправить эту проблему, вам необходимо использовать malloc, определенный в stdlib.h.

int *func(int n) {
   int *v = malloc(sizeof(int) * n); // allocate memory for n elements

   v[0] = 1;
   v[1] = 2;
   v[2] = 3;

   return v;   // this will now work
}

int main() {
   int *v;
   v = func(3); // this will work
   // print values in v
   free(v);
   return 0;
}

причина, по которой это работает, заключается в том, что память, выделенная с помощью malloc, выделяется в куче, что означает, что она сохраняется на протяжении всей программы, если вы не освободите ее самостоятельно (это означает, что вам нужно освободить память в конце с помощью функции free ).

0 голосов
/ 13 июля 2020

У вас большое количество проблем, Неопределенное поведение является наиболее критическим:

n -= 1; 
for(i=0;i<=n;i++)
{
    b[i]=a[n-i];
}

Когда i == n, вы индексируете один за пределами вашего b[] массива . Все массивы в C имеют нулевой индекс, поэтому ваши пределы l oop равны 0 <= i < n. Используя i<=n, вы l oop слишком много раз.

Вы не можете проверить возврат любого пользовательского ввода. Попробуйте ввести «один» или случайно набрать 'r' вместо 4 и посмотрите, что произойдет. Вы должны проверять возврат для каждого пользовательского ввода и обрабатывать ошибку. Что произойдет, если пользователь введет 1, 2, 'r', 5? Вы также должны очистить stdin от любых посторонних символов, иначе они снова укусят вас при следующем вводе.

Не используйте conio.h. Это делает ваш код на 100% непереносимым. Вы можете использовать функции из stdio.h для своих нужд.

Тем не менее, когда вам нужно выполнять повторяющиеся задачи, такие как ввод целочисленных значений, напишите для этого короткую функцию. Вы можете написать такой, который принимает указатель на целое число для заполнения и указатель на приглашение для отображения и возвращает 0 в случае успеха или -1, если пользователь отменяет ввод, создавая руководство EOF с помощью Ctrl + d на Linux или Ctrl + z на windows. Вы можете добавить вспомогательную функцию в пустой stdin, например

void empty_stdin (void)
{
    int c = getchar();
    
    while (c != '\n' && c != EOF)
        c = getchar();
}

int getint (int *n, const char *prompt)
{
    int rtn;
    
    for (;;) {
        fputs (prompt, stdout);
        rtn = scanf ("%d", n);
        if (rtn == EOF) {
            fputs ("  (user canceled input)\n", stderr);
            return -1;
        }
        else if (rtn == 0) {
            fputs ("  error: invalid integer input.\n", stderr);
            empty_stdin();
        }
        else
            break;
    }
    empty_stdin();
    
    return 0;
}

Остальная часть вашей программы для чтения массива в a[] и обратного его в b[] просто:

int main (void) {
    
    int i = 0, n;
    
    if (getint (&n, "Enter array parameter: ") == -1)
        return 0;
    
    int a[n], b[n];
    
    for (i = 0; i < n; i++) {
        char buf[128];
        sprintf (buf, "enter value for a[%d]: ", i+1);
        if (getint (&a[i], buf) == -1)
            return 0;
    }
    for (i = 0; i < n; i++)
        b[i] = a[n - 1 - i];
    
    puts ("\nvalue of array b[]:");
    for (i = 0; i < n; i++)
        printf (" %d", b[i]);
    putchar ('\n');

#if defined (_WIN32) || defined (_WIN64)
    getchar();  /* hold terminal open on windows - type any char, hit return */
#endif
}

Пример использования / вывода

Все допустимые вводы:

$ ./bin/getarray
Enter array parameter: 5
enter value for a[1]: 5
enter value for a[2]: 4
enter value for a[3]: 3
enter value for a[4]: 2
enter value for a[5]: 1

value of array b[]:
 1 2 3 4 5

Ошибки при вводе:

$ ./bin/getarray
Enter array parameter: foo
  error: invalid integer input.
Enter array parameter: 5
enter value for a[1]: 5
enter value for a[2]: four
  error: invalid integer input.
enter value for a[2]: 4
enter value for a[3]: 3
enter value for a[4]: I'm getting tired of this game...
  error: invalid integer input.
enter value for a[4]: 2
enter value for a[5]: 1

value of array b[]:
 1 2 3 4 5

Пользователь отменяет ввод :

$ ./bin/getarray
Enter array parameter: 5
enter value for a[1]: 5
enter value for a[2]: 4
enter value for a[3]: 3
enter value for a[4]:   (user canceled input)

Посмотрите все и дайте мне знать, если у вас возникнут дополнительные вопросы.

0 голосов
/ 13 июля 2020

Инициализация массива в C:

int ary[5] {1,2,3,4,5};

Это недопустимый синтаксис в c (это действительно в c ++).

существует 3 способа инициализации c массивы:

  1. с фигурными скобками {} как и вы (int ary[] = {1,2,3,4,5};)
  2. итерация элементов массива один за другим для l oop и инициализация каждого из них из них.
  3. через: memset(void *str, int c, size_t n);, для заполнения всего массива одним и тем же значением. например, если я хочу инициализировать массив с помощью 0x0, тогда вызов memset будет выглядеть так: memset(arr, 0x0, sizeof(arr));

Что касается вашего кода:

  1. для каждого scanf(..) в коде вы должны проверить и подтвердить scanf("%d",&n);, вернуть / ошибки и пользовательский ввод в n, прежде чем делать какие-либо изменения в вашем коде. Как проверить? см. позже.
  2. В вашей ситуации лучше ограничить ввод пользователя n и проверить, что n в определенном диапазоне (N_min <= n <= N_max), вместо того, чтобы вызывать выделение огромного массива в стеке в случае n было установлено на максимальное значение пользователем!
if(scanf("%d",&n) == EOF){
    /*errors ocuured*/
    f_invoke_error_handling_rotuine(); 
}

В f_invoke_error_handling_rotuine(..) вы можете делать все, что нужно вашему коду, возможно, abort() с сообщением об ошибке, возможно, установив значение по умолчанию значения n ... et c.

см. ссылку на memset и scanf в man7.org: scanf , memset

...