Как передать указатель на структуру в функцию с помощью языка C?

я новичок в разработке с c. наверняка наступит день, когда мне понадобится твоя помощь. И я думаю, что это время сейчас :)

Что я пытаюсь сделать: я экспериментирую с MySQL Api в C. Для этого я хотел использовать структуру для хранения моего SQLQuery и всех его параметров, например. пользовательские данные для выбора или вставки.

Затем с помощью нескольких функций я хотел добавить, удалить и скомпилировать строку, чтобы использовать ее в запросе.

Чтобы использовать мою функцию createSqlQuery, я хотел бы передать в нее ссылку на мою структуру SQLQuery и изменить ее внутри функции. После завершения этой функции она не должна выходить за рамки и по-прежнему может использоваться в основной функции.

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

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

Сообщение об ошибке:

main.c:127:10: ошибка: запрос члена «addParam» в чем-то, что не является структурой или объединением

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

Это то, что у меня есть до сих пор:

typedef struct sqlQuery sqlQuery;

struct sqlQuery{
    char *queryS;
    char **params; //array of array of chars to hold the params to replace %? in the query
    bool (*addParam)(sqlQuery*, char*);
    bool (*compile)(sqlQuery*);
};

int main(){
/* ...  */
    sqlQuery *testQuery = NULL;
    printf("%p\n", &testQuery);
    printf("%p\n", testQuery);
    createSqlQuery(&testQuery,"SELECT * FROM test WHERE name = '%?'");
    printf("%p\n", testQuery);
    if (testQuery != NULL) printf("working, testQuery still assigned");
    //testQuery->addParam(testQuery, "test");
    //freeSqlQuery(testQuery);

    exit(EXIT_SUCCESS);
}

bool createSqlQuery(sqlQuery **query, char *queryString){
    *query = (struct sqlQuery *) malloc(sizeof(struct sqlQuery));  //get heapspace for sqlQuery Struct
    printf("%p\n", *query);
    //query->addParam = __sqlQueryAddParam;      //link param function pointer
    //query->compile = __compileSqlQuery;        //link compile function pointer
    *query->queryS = queryString;               //save pointer to query String
    //^^^ this is where the error occurs

    return true;
}

Я также пробовал комбинации и варианты:

(sqlQuery *)*query->queryS = queryString;

с ** или &...

Я надеюсь, вы понимаете, с чем я борюсь, я думаю, это просто, но я действительно не могу понять это :)

Заранее спасибо!


person Daniel    schedule 04.06.2013    source источник
comment
Не могли бы вы быстро проверить работоспособность и изменить typedef struct sqlQuery sqlQuery; struct sqlQuery { ... }; на typedef struct { ... } sqlQuery;?   -  person slugonamission    schedule 04.06.2013
comment
comment
Ах да, тогда уберите struct из всех вариантов использования struct sqlQuery.   -  person slugonamission    schedule 04.06.2013
comment
slugonamission: вы правы. У меня их изначально не было. позже добавил их, чтобы проверить, есть ли разница. раскрутиться: упс :) скопировал это из другого вопроса...   -  person Daniel    schedule 04.06.2013


Ответы (4)


Это вызвано приоритетом оператора, поскольку оператор доступа к члену -> имеет более высокий приоритет, чем оператор разыменования *. Изменять:

*query->queryS = queryString; 

to:

(*query)->queryS = queryString;

Другой:

  • Не приводить возвращаемое значение из malloc().
  • Код назначает адрес строкового литерала, доступного только для чтения, переменной char*. Используйте const char* или скопируйте строку (используя malloc()/strcpy() или strdup(), если это предусмотрено вашей реализацией.
  • Не забудьте free() что было malloc()d.
person hmjd    schedule 04.06.2013

Для большей простоты попробуйте

bool createSqlQuery(struct sqlQuery **ptrresultquery, char *queryString)
{
    struct sqlQuery *query = (struct sqlQuery *) malloc(sizeof(struct sqlQuery));  //get heapspace for sqlQuery Struct

     query->addParam = __sqlQueryAddParam;      //link param function pointer
     query->compile = __compileSqlQuery;        //link compile function pointer
     query->queryS = queryString;               //save pointer to query String

     // write the local pointer back via parameter ptr
     *ptrresultquery= query;

     return true;
}

В противном случае то, что вы хотите сделать с вашим синтаксисом,

    (*ptrresultquery)->queryS= queryString;
person Nicholaz    schedule 04.06.2013

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

Но если вы настаиваете на возврате логического значения и принятии указателя на указатель, проще работать с временным указателем внутри функции:

bool createSqlQuery(sqlQuery **query, char *queryString){
  struct sqlQuery *q = malloc(sizeof *q);
  if( q != NULL ) {
    q->addParam = __sqlQueryAddParam;
    q->compile = __compileSqlQuery;        //link compile function pointer
    q->queryS = queryString;
    *query = q;
  }
  return q != NULL;
}

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

person unwind    schedule 04.06.2013
comment
привет, я начал с этого как моей первой идеи :) sqlQuery* createSqlQuery(char *queryString){} я изменил его, чтобы я мог легко выполнить if(!createSqlQuery(...)){/*обработка ошибок*/} - person Daniel; 04.06.2013

(*query)->queryS = queryString; сделает работу

И используйте прототипы, если вы вызываете функцию после main

bool createSqlQuery(sqlQuery **query, char *queryString);
person David Ranieri    schedule 04.06.2013
comment
спасибо за эту подсказку. Я закомментировал их в этом примере! Следующее, чему нужно научиться, это как разделить эти вещи на .h и .c и использовать работающий Makefile :) - person Daniel; 04.06.2013