В C - как определить функции с указателями в качестве аргументов? - PullRequest
0 голосов
/ 13 марта 2019

Я пытаюсь определить функцию с именем scanEntries, которая принимает аргумент int и аргумент указателя. Когда я попытался скомпилировать его, я получил сообщение об ошибке:

"warning: passing argument 2 of ‘scanEntries’ makes pointer from integer 
 without a cast [enabled by default]"

Я попытался найти это сообщение об ошибке здесь, но получил только результаты о существующих функциях, связанных со строками, а не о пользовательских функциях. Я никогда не пробовал писать функции с указателями в качестве аргументов; Что я делаю неправильно? Что именно нужно здесь бросить и как мне это сделать?

 /* function to scan any integer value */
int scanInt() {
    int output;
    scanf("%d\n", output);
    return(output);
}

/* scanInt but as one entry out of a group */
int scanEntry(int number, int total) {
    printf("Please enter score %d of %d: ", number+1, total);
    return(scanInt());
}

/* scanEntry for an entire dynamic array) */
void scanEntries(int total, int *p) {
    int number;
    for(number = 0; number < total; number++) {
        *(p + number) = scanEntry(number, total);
        /* for testing */
        printf("%d", *(p + number));
    }
}

Здесь вызывается scanEntries, плюс еще одна функция, не показанная выше, которую я использовал здесь:

/* scanInt but with a prompt to enter size */
int enterSize() {
    printf("Please enter size of array: ");
    return(scanInt());
}

int main() {
    /* entering initial size, done in a separate function */
    int initSize = enterSize();
    int *p; /* p is an int pointer */
    p = calloc(initSize, sizeof(int));
    printf("%d", initSize);

    scanEntries(enterSize(), *p);
}

Ответы [ 4 ]

1 голос
/ 13 марта 2019

Изменение:

scanEntries(enterSize(), *p);

Кому:

scanEntries(enterSize(), p);

Пояснение

Вы должны передать указатель в качестве второго параметра функции.p - указатель на int, таким образом, ваш вызов передает int вместо указателя.Вот почему у вас есть предупреждение.

1 голос
/ 13 марта 2019

Определение вашей функции в порядке. Проблема в том, как вы это называете.

В вашей функции main вы объявляете p указателем:

int *p; /* p is an int pointer */

Но тогда вы разыменовываете этот указатель при вызове scanEntries:

scanEntries(enterSize(), *p);

Вы фактически передаете int в функцию вместо указателя на int, поэтому компилятор пытается преобразовать int в указатель для соответствия параметру. Вот что говорит вам предупреждение.

Поскольку функция ожидает int *, просто передайте ее непосредственно функции. Кроме того, вам не нужно снова звонить enterSize здесь, так как вы уже получили размер. используйте initSize вместо:

scanEntries(initSize, p);

Кроме того, это неправильно:

scanf("%d\n", output);

Спецификатор формата %d ожидает указатель на int, но вы просто передаете простое int. Использование неправильного типа для спецификатора формата вызывает неопределенное поведение .

Вы хотите передать адрес output функции, чтобы она обновлялась. Кроме того, \n в формате заставит вашу программу запрашивать дополнительный ввод. Это не нужно.

scanf("%d", &output);
1 голос
/ 13 марта 2019

Это основная суть того, как:

  • Объявление функции, которая принимает указатель
  • Передача указателя на функцию

МинимальнаяПример:

#include <stdio.h>

void incrementMyInt(int *p) {
  // increment the value of the int that p points to
  (*p)++;
}

int main() {
  int n1 = 3;
  int *n2 = malloc(sizeof(int));
  *n2 = 7;
  incrementMyInt(&n1); // pass the address of n
  incrementMyInt(n2);
  printf("n1 is %d\n", n);
  printf("n2 is %d\n", *n2);
  return 0;
}

Он выводит n1 is 4 и n2 is 8.

0 голосов
/ 13 марта 2019

Продолжая мои комментарии - если вы объявите int *p; и ваш прототип - void scanEntries(int total, int *p), вы просто называете его как scanEntries(initSize, p); (здесь нет '*') "warning: passing argument 2 of ‘scanEntries’ makes pointer from integer without a cast [enabled by default]" из-за вашей попытки передать *p, который разыменовывает целочисленный указатель 'p', что приводит к int значение вместо указателя на int .

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

В main() вам не следует звонить enterSize() во второй раз, вместо этого:

    scanEntries (initSize, p);

Кроме того, вы должны проверить КАЖДОЕ распределение и КАЖДЫЙ ввод, например,

    p = calloc(initSize, sizeof(int));
    if (!p) {   /* VALIDATE EVERY ALLOCATION */
        perror ("calloc-p");
        return 1;
    }

и, наконец, если вы выделите память, выработаете хорошие привычки и обеспечите ее free, когда она больше не нужна, например,

    free (p);   /* don't forget to free what you allocate */
}

В scanInt() необходимо указать указатель от output до scanf, например,

    if (scanf ("%d", &output) != 1) { /* VALIDATE EVERY INPUT */
        fputs ("error: invalid input - not an integer.\n", stderr);
        exit (EXIT_FAILURE);
    }

( примечание: &output в scanf вызове)

Кроме того, хотя и эквивалентно, не используйте обозначение указателя для *(p + number), вместо этого просто используйте p[number], оно более читабельно.

Если сложить все вместе, вы можете сделать:

#include <stdio.h>
#include <stdlib.h>

/* function to scan any integer value */
int scanInt (void)
{
    int output;

    if (scanf ("%d", &output) != 1) { /* VALIDATE EVERY INPUT */
        fputs ("error: invalid input - not an integer.\n", stderr);
        exit (EXIT_FAILURE);
    }

    return (output);
}

/* scanInt but as one entry out of a group */
int scanEntry (int number, int total)
{
    printf ("Please enter score %d of %d: ", number+1, total);

    return (scanInt());
}

/* scanEntry for an entire dynamic array) */
void scanEntries (int total, int *p)
{
    int number;

    for (number = 0; number < total; number++) {
        p[number] = scanEntry (number, total);
#ifdef TESTING
        printf (" scanEntries testing - %d\n", p[number]);
#endif
    }
}

/* scanInt but with a prompt to enter size */
int enterSize (void)
{
    printf ("Please enter size of array: ");
    return (scanInt());
}

int main (void) {

    /* entering initial size, done in a separate function */
    int initSize = enterSize(),
        *p;                             /* p is an int pointer */
    p = calloc(initSize, sizeof(int));
    if (!p) {   /* VALIDATE EVERY ALLOCATION */
        perror ("calloc-p");
        return 1;
    }
    printf ("%d\n", initSize);

    scanEntries (initSize, p);

    printf ("%d entries read:\n\n", initSize);
    for (int i = 0; i < initSize; i++)
        printf ("p[%2d] : %d\n", i, p[i]);

    free (p);   /* don't forget to free what you allocate */
}

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

( примечание: вы можете добавить -DTESTING к опциям вашего компилятора, чтобы определить TESTING для активации дополнительного кода.)

$ ./bin/scanentries
Please enter size of array: 4
4
Please enter score 1 of 4: 1
Please enter score 2 of 4: 2
Please enter score 3 of 4: 3
Please enter score 4 of 4: 4
4 entries read:

p[ 0] : 1
p[ 1] : 2
p[ 2] : 3
p[ 3] : 4

Использование памяти / проверка ошибок

В любом написанном вами коде, который динамически распределяет память, у вас есть 2 обязанностей относительно любого выделенного блока памяти: (1) всегда сохраняйте указатель на начальный адрес для блока памяти, так что, (2) он может быть освобожден , когда он больше не нужен.

Крайне важно, чтобы вы использовали программу проверки ошибок памяти, чтобы гарантировать, что вы не пытаетесь получить доступ к памяти или писать за пределами / за пределами выделенного блока, пытаться прочитать или основать условный переход на неинициализированном значении и, наконец, , чтобы подтвердить, что вы освобождаете всю выделенную память.

Для Linux valgrind - нормальный выбор. Для каждой платформы есть похожие проверки памяти. Все они просты в использовании, просто запустите вашу программу через него.

$ valgrind ./bin/scanentries
==11795== Memcheck, a memory error detector
==11795== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==11795== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==11795== Command: ./bin/scanentries
==11795==
Please enter size of array: 4
4
Please enter score 1 of 4: 1
Please enter score 2 of 4: 2
Please enter score 3 of 4: 3
Please enter score 4 of 4: 4
4 entries read:

p[ 0] : 1
p[ 1] : 2
p[ 2] : 3
p[ 3] : 4
==11795==
==11795== HEAP SUMMARY:
==11795==     in use at exit: 0 bytes in 0 blocks
==11795==   total heap usage: 1 allocs, 1 frees, 16 bytes allocated
==11795==
==11795== All heap blocks were freed -- no leaks are possible
==11795==
==11795== For counts of detected and suppressed errors, rerun with: -v
==11795== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Всегда подтверждайте, что вы освободили всю выделенную память и что ошибок памяти нет.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...