Вопрос новичка. Как передать указатели на функцию в C? - PullRequest
2 голосов
/ 31 января 2011

Я только начал изучать C (исходя из фона C #). Для своей первой программы я решил создать программу для расчета факторов.Мне нужно передать указатель на функцию, а затем обновить соответствующую переменную.

Я получаю ошибку «Конфликтующие типы для findFactors», я думаю, что это потому, что я не показал, что хочу передатьуказатель в качестве аргумента, когда я объявляю функцию findFactors.Любая помощь будет принята с благодарностью!

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

int *findFactors(int, int);

int main (int argc, const char * argv[]) 
{
    int numToFind;

do {
    printf("Enter a number to find the factors of: ");
    scanf("%d", &numToFind);    
} while (numToFind > 100);

    int factorCount;
findFactors(numToFind, &factorCount);

return 0;
}

int *findFactors(int input, int *numberOfFactors)
{
int *results = malloc(input);
int count = 0;
for (int counter = 2; counter < input; counter++) {
    if (input % counter == 0){
        results[count] = counter;
        count++;
        printf("%d is factor number %d\n", counter, count);
    }
}

return results;
}

Ответы [ 5 ]

3 голосов
/ 31 января 2011

Измените объявление, чтобы оно соответствовало определению:

int *findFactors(int, int *);
2 голосов
/ 31 января 2011

Я прошу прощения за добавление еще одного ответа, но я не думаю, что кто-то охватил все вопросы, которые необходимо охватить в вашем вопросе.

1) Всякий раз, когда вы используете malloc() для динамического выделения некоторой памяти,Вы также должны free() это, когда вы закончите.Операционная система обычно приводит в порядок после вас, но учтите, что у вас есть процесс во время вашего исполняемого файла, который использует некоторое количество памяти.Когда указанный процесс завершен, если вы free() этой памяти, ваш процесс имеет больше доступной памяти.Это касается эффективности.

Чтобы использовать бесплатно правильно:

int* somememory = malloc(sizeyouwant * sizeof(int));
// do something
free(somememory);

Легко.

2) Всякий раз, когда вы используете malloc, как уже отмечали другие, фактическое распределение в байтах, так что выдолжен сделать malloc(numofelements*sizeof(type));.Есть еще одна, менее широко используемая функция под названием calloc, похожая на эту calloc(num, sizeof(type));, которую, возможно, легче понять. calloc также инициализирует вашу память на ноль .

3) Вам не нужно приводить тип возвращаемого значения malloc.Я знаю, что многие книги по программированию предлагают вам и C ++ мандаты, которые вы должны (но в C ++ вы должны использовать new / delete).См. этот вопрос .

4) Ваша сигнатура функции действительно неверна - сигнатуры функций должны совпадать с их функциями.

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

Еще один момент, рассмотрим эту функцию:

int* badfunction()
{
    int x = 42;
    int *y = &x;
    return y;
}

Это плохо, плохо, плохо.Здесь происходит то, что мы создаем и возвращаем указатель на x, который существует, пока вы находитесь в badfunction.Когда вы возвращаетесь, у вас есть адрес переменной, которая больше не существует , потому что x обычно создается в стеке.Вы узнаете больше об этом со временем;сейчас просто подумайте, что переменная не существует вне ее функции.

Обратите внимание, что int* y = malloc(... - это другой случай - память создается в куче из-за malloc и, следовательно, сохраняется в конце указанногоfunction.

Что бы я порекомендовал в качестве сигнатуры функции?Я бы на самом деле пошел с функцией shybovycha с небольшой модификацией:

int findFactors(int* factors, const int N);

Мои изменения - это просто личные предпочтения.Я использую const, чтобы я знал, что что-то является частью ввода функции.Это не обязательно просто с помощью int, но если вы передаете указатели, помните, что исходная память может быть изменена, если вы не используете const перед этим, и ваш компилятор должен предупредить вас, если вы попытаетесь ее изменить.Так что в данном случае это просто привычка.

Второе изменение заключается в том, что я предпочитаю выходные параметры слева, потому что я всегда так думаю, т. Е. output = func(input).

Почему вы можете изменять аргументы функциикогда указатель используется?Потому что вы передали указатель на переменную.Это просто адрес памяти - когда мы «разыменовываем» его (обращаемся к значению по этому адресу), мы можем его изменить.Технически говоря, C строго передается по значению.Сами указатели являются переменными, содержащими адреса памяти, и содержимое этих переменных копируется в вашу функцию.Поэтому обычная переменная (скажем, int) - это просто копия того, что вы передали. int* factors - это копия адреса в переменной указателя, которую вы передаете. По замыслу и оригинал, и эта копия указывают на одно и то жепамять, поэтому, когда мы разыменовываем их, мы можем редактировать эту память как в вызывающей, так и в исходной функции.

Надеюсь, это прояснит некоторые вещи.

1 голос
/ 31 января 2011

РЕДАКТИРОВАТЬ: нет ссылки на C (функция C ++)

Не забудьте изменить numberOfFactors в методе (или удалить этот параметр, если он бесполезен). Подпись в начале вашего файла также должна соответствовать подписи реализации в конце (это ошибка, которую вы получаете).

Наконец, ваш malloc для результатов неверен. Вам нужно сделать это:

int *results = malloc(input * sizeof(int));
0 голосов
/ 31 января 2011

int *findFactors(int, int); строка говорит, что вы хотите вернуть указатель из этой функции (лучше использовать звездочки ближе к имени типа: int* moo(); - я думаю, это предотвращает недоразумения).

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

И последняя ваша ошибка: malloc(X) выделяет X байт , поэтому, если вы хотите выделить память для некоторого массива, вы должны использовать malloc(N * sizeof(T));, где N - это размер ваш массив и T это его тип. Например: если вы хотите иметь int *a, вы должны сделать это: int *a = (int*) malloc(10 * sizeof(int));.

А теперь вот ваш исправленный код (как для меня):

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

int findFactors(int, int*);

int main(int argc, char **argv) 
{
  int numToFind, *factors = 0, cnt = 0;

  do 
  {
    printf("Enter a number to find the factors of: ");
    scanf("%d", &numToFind);    
  } while (numToFind > 100);

  cnt = findFactors(numToFind, factors);

  printf("%d has %d factors.\n", numToFind, cnt);

  return 0;
}

int findFactors(int N, int* factors)
{
  if (!factors)
    factors = (int*) malloc(N * sizeof(int));

  int count = 0;

  for (int i = 2; i < N; i++) 
  {
    if (N % i == 0)
    {
      factors[count++] = i;
      printf("%d is factor number #%d\n", i, count);
    }
  }

  return count;
}

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

0 голосов
/ 31 января 2011
int* ip   <- pointer to a an int
int** ipp <- pointer to a pointer to an int.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...