#c
#c
Вопрос:
Я уже некоторое время пытаюсь и, похоже, не могу заставить это работать:
char** fetch (char *lat, char*lon){
char emps[10][50];
//char** array = emps;
int cnt = -1;
while (row = mysql_fetch_row(result))
{
char emp_det[3][20];
char temp_emp[50] = "";
for (int i = 0; i < 4; i ){
strcpy(emp_det[i], row[i]);
}
if ( (strncmp(emp_det[1], lat, 7) == 0) amp;amp; (strncmp(emp_det[2], lon, 8) == 0) ) {
cnt ;
for (int i = 0; i < 4; i ){
strcat(temp_emp, emp_det[i]);
if(i < 3) {
strcat(temp_emp, " ");
}
}
strcpy(emps[cnt], temp_emp);
}
}
}
mysql_free_result(result);
mysql_close(connection);
return array;
Да, я знаю, что array = emps закомментирован, но без комментариев он говорит мне, что типы указателей несовместимы. Это, на случай, если я забыл упомянуть, находится в функции типа char **, и я хочу, чтобы она возвращала emps [10] [50] или следующую лучшую вещь. Как я могу это сделать? Спасибо!
Комментарии:
1. Пожалуйста, покажите полную функцию, включая параметры и возвращаемый тип.
2. Вопросы, обращающиеся за помощью по отладке («почему этот код не работает?»), должны включать желаемое поведение, конкретную проблему или ошибку и кратчайший код, необходимый для ее воспроизведения в самом вопросе. Вопросы без четкой формулировки проблемы не полезны для других читателей. Смотрите: Как создать минимальный, полный и проверяемый пример.
3.
char emp_det[3][20];
требуется 4 элемента в его первом измерении, если вы индексируете его сemp_det[3]
помощью, как вы делаете вi
цикле.4. Пусть это автоматическая переменная, указатель не является массивом!
char **
это совсем другой тип, чемchar[R][C]
.
Ответ №1:
Выражение типа массива T [N][M]
не распадается на T **
— оно распадается на тип T (*)[M]
(указатель на M
массив элементов).
Во-вторых, вы пытаетесь вернуть адрес массива, который является локальным для функции; после завершения работы функции emps
массив больше не существует, и любой указатель на него становится недействительным.
Вероятно, вам было бы лучше передать целевой массив в качестве параметра функции и заставить функцию записать в него, а не создавать новый массив внутри функции и возвращать его. Вы могли бы динамически распределять массив, но тогда вы выполняете танец управления памятью, и лучший способ избежать проблем с управлением памятью — избегать управления памятью.
Итак, ваше определение функции будет выглядеть следующим образом
void fetch( char *lat, char *lon, char emps[][50], size_t rows ) { ... }
и ваш вызов функции будет выглядеть так
char my_emps[10][50];
...
fetch( amp;lat, amp;lon, my_emps, 10 );
Ответ №2:
То, что вы пытаетесь, не сработает, даже если вы попытаетесь выполнить приведение, потому что вы будете возвращать адрес локальной переменной. Когда функция возвращается, эта переменная выходит за пределы области видимости, а память, которую она использовала, больше недействительна. Попытка разыменования этого адреса приведет к неопределенному поведению.
Что вам нужно, так это использовать динамическое выделение памяти для создания структуры данных, которую вы хотите вернуть:
char **emps;
emps = malloc(10 * sizeof(char *));
for (int i=0; i<10; i ) {
emps[i] = malloc(50);
}
....
return emps;
Вызывающей функции потребуется free
память, созданная этой функцией. Ему также необходимо знать, сколько распределений было выполнено, чтобы он знал, сколько раз вызывать free
.
Комментарии:
1. Спасибо! Казалось, это помогло. Теперь я понял проблему с локальной переменной, на которую будет невозможно указать после выполнения функции. По какой-то причине сейчас я получаю всю строку в базе данных, но это все равно нечто большее, чем у меня было.
2. Поцарапайте это, запустив без сна. Не понял, какой код я вставил, лол. Еще раз спасибо
Ответ №3:
Если вы нашли способ преобразовать char emps[10][50];
в char *
или char **
- вы не сможете правильно сопоставить данные (размеры и т. Д.). многомерные массивы символов таковыми не
char **
являются . Это просто непрерывная память с вычислением индекса. Лучше подходит дляchar *
BTW - но самая большая проблема заключалась
emps
бы в том, что это выходило бы за рамки, и автоматическая память была бы перераспределена в какую-то другую переменную, уничтожая данные.
Однако есть способ сделать это, если ваши размеры действительно фиксированы:
Вы можете создать функцию, которая принимает a char[10][50]
в качестве параметра ввода / вывода (вы не можете возвращать массив, это запрещено компилятором, вы могли бы вернуть структуру, содержащую массив, но это было бы неэффективно)
Пример:
void myfunc(char emp[10][50])
{
emp[4][5] = 'a'; // update emp in the function
}
int main()
{
char x[10][50];
myfunc(x);
// ...
}
main
Программа отвечает за память x
, которая передается как изменяемая в myfunc
подпрограмму: она безопасна и быстра (без копирования в память)
Хорошая практика: определите такой тип typedef char matrix10_50[10][50];
, чтобы объявления были более логичными.
Основным недостатком здесь является то, что размеры фиксированы. Если вы хотите использовать myfunc
для другого набора измерений, вам нужно скопировать / вставить его или использовать макросы для определения обоих (например, шаблон для бедных).
Редактировать
хороший комментарий предполагает, что некоторые компиляторы поддерживают переменный размер массива. Таким образом, вы могли бы передавать измерения вместе с вашим неограниченным массивом:
void myfunc(int rows, int cols, char emp[rows][cols])
Протестировано, работает gcc 4.9
(возможно, и в более ранних версиях) только с кодом C, а не С и не в .cpp
файлах, содержащих обычный C (но все же превосходит громоздкие malloc/free
вызовы)
Комментарии:
1. Я согласен, что лучше всего передать массив функции. Если у вас есть компилятор, который поддерживает массивы переменной длины , вы можете объявить функцию как
void myfunc(int rows, int cols, char emp[rows][cols])
, и тогда массив может быть любого размера.2. @user3386109: очень интересно! но, похоже, не удается сделать это с помощью gcc или даже g -std=C 11. У вас есть пример компиляторов, которые могут это сделать?
3. @user3386109 без вызова массивов переменной длины, некоторый ответ здесь позволяет избежать передачи первого измерения. На полпути :):
func(int rows, char emp[][50])
4. Да, это тоже хороший ответ, но gcc должен работать .
5. На самом деле это работает. Просто я поместил свой код в вызываемый файл
.cpp
иgcc
молча переключился на C . Переименовал в.c
, и это сработало! Сегодня я многому научился!
Ответ №4:
Чтобы понять, почему вы не можете этого сделать, вам нужно понять, как работают матрицы в C.
Матрица, скажем, ваш символ emps[10] [50] представляет собой непрерывный блок памяти, способный хранить 10 * 50 = 500 символов (представьте массив из 500 элементов). Когда вы обращаетесь к emps[i][j], он обращается к элементу с индексом 50 *i j в этом «массиве» (возьмите лист бумаги и ручку, чтобы понять, почему). Проблема в том, что 50 в этой формуле — это количество столбцов в матрице, которое известно во время компиляции из самого типа данных. Когда у вас есть символ **, компилятор не может узнать, как получить доступ к случайному элементу в матрице.
Способ построения матрицы таким образом, чтобы она была символом **, заключается в создании массива указателей на символ, а затем выделении каждого из этих указателей:
char **emps = malloc(10 * sizeof(char*)); // create an array of 10 pointers to char
for (int i = 0; i < 10; i )
emps[i] = malloc(50 * sizeof(char)); // create 10 arrays of 50 chars each
Дело в том, что вы не можете преобразовать матрицу в двойной указатель аналогично тому, как вы преобразуете массив в указатель.
Ответ №5:
Другая проблема: возврат 2D-матрицы как ‘char **’ имеет смысл только в том случае, если матрица реализована с использованием массива указателей, каждый указатель указывает на массив символов. Как объяснялось ранее, 2D-матрица в C — это просто плоский массив символов. Максимум, что вы можете вернуть, это указатель на запись [0][0], ‘char *’. Существует несоответствие в количестве косвенных ссылок.
Комментарии:
1. Смотрите ответ @Olaf. Вы можете вернуть символ [R][C], но это отличается от возврата символа ** .