#c #pointers #linked-list
#c #указатели #связанный список
Вопрос:
Я работаю над небольшой тестовой программой, которая может выполнять 2 функции в связанном списке:
- добавьте что-нибудь в связанный список.
- получить то, что было добавлено.
Итак, я написал 2 функции, которые могут выполнять именно это. Однако это не работает. Если я вызываю функцию append_work()
, она выводит, что она добавила работу, а также правильные значения, которые я передал. Однако впоследствии, похоже, он неправильно устанавливает указатель на следующую структуру. Я не знаю, почему это происходит.
Аналогичная вещь происходит, когда я вызываю get_work()
, что он правильно выводит текущую работу, но не устанавливает ее на следующую. outptr существует только для того, чтобы он возвращал структуру для выполняемой работы, в то время как stil настраивает work_travel на следующий!
Вероятно, я упускаю что-то действительно очевидное с указателями, но я этого не вижу…
Вот код. он компилирует:
#define _POSIX_C_SOURCE 200809L
#define ERRNO_BUFSIZE 256
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
int strerror_r(int errnum, char *buf, size_t buflen);
typedef struct work work;
struct work {
char *str;
int i;
work *next;
};
int append_work(work *ptr, char *work, int i) {
char strerror_buf[ERRNO_BUFSIZE];
ptr->next = malloc(sizeof(work));
if (ptr == NULL) {
strerror_r(errno, strerror_buf, ERRNO_BUFSIZE);
printf("malloc() err: %sn",strerror_buf);
return -1;
}
ptr = ptr->next;
ptr->str=work;
ptr->i=i;
printf("appending work: %sn",ptr->str);
ptr->next = NULL;
return 0;
}
int get_work(work *inptr, work *outptr) {
if (inptr == NULL) {
printf(" No work found...n");
return -1;
} else {
outptr = inptr;
printf(" work found: str: %s|| int: %dn",inptr->str, inptr->i);
inptr = inptr->next;
return 0;
}
}
int main() {
char strerror_buf[ERRNO_BUFSIZE];
work *root;
work *work_travel;
work *add_work;
work *curr_work;
root = malloc(sizeof(work));
if (root == NULL) {
strerror_r(errno, strerror_buf, ERRNO_BUFSIZE);
printf("malloc() err: %sn",strerror_buf);
exit(1);
}
root->str="work 0";
root->i=0;
work_travel = root;
add_work = root;
append_work(add_work, "work 1", 1);
append_work(add_work, "work 2", 2);
append_work(add_work, "work 3", 3);
append_work(add_work, "work 4", 4);
append_work(add_work, "work 5", 5);
append_work(add_work, "work 6", 6);
append_work(add_work, "work 7", 7);
append_work(add_work, "work 8", 8);
append_work(add_work, "work 9", 9);
get_work(work_travel, curr_work);
get_work(work_travel, curr_work);
get_work(work_travel, curr_work);
exit(1);
}
Комментарии:
1. вам может помочь что-то вроде двойного указателя. 🙂
Ответ №1:
Вы никогда не возвращаете новый заголовок для списка, вы меняетесь ptr
внутри append_work()
, но значение add_work
in main()
не меняется.
Вместо этого вы должны вернуть новый заголовок списка.
Это связано с тем, что C строго вызывается по значению; аргумент является копией того же значения в контексте вызывающего объекта, и изменение копии не влияет на значение вызывающего объекта. Тип значения не имеет значения, это всегда копия.
Комментарии:
1. Я подумал, что если я изменю указатель в функции, которая должна сохраняться в main? Почему это не так
2. Если это строго вызов по значению. тогда почему моя работа по добавлению все еще добавляется, если я выполняю вручную в main?
3. Если вы измените содержимое объекта, указатель, на который указывает это изменение, сохранится, однако вы меняете то, что вы передаете. И, как указано в ответе, это всего лишь копия исходного указателя.
4. @RG337 Извините, я не совсем понимаю, что вы имеете в виду. Возможно, вам следует опубликовать отдельный вопрос с точным кодом для этого случая, и люди посмотрят.
5. @LaszloLadanyi Я вижу, спасибо. По сути, то, что вы говорите, как только я выйду за пределы указателя на фактическую ячейку памяти, оно сохранится. на самом деле это очевидно…
Ответ №2:
Прежде всего, наличие «struct work», типа с именем «work» и переменной с именем «work» — это действительно плохой стиль программирования.
Тем не менее, проблема в том, что inptr
это локальная переменная get_work
, ее изменение не изменится work_travel
при вызове get_work(work_travel, curr_work)
. Вы должны каким-то образом возвращать обновленное значение, либо как возвращаемое значение из get_work, например (хотя с этим решением вы теряете флаг успеха, а не используете его :-)):
work *get_work (work *inptr, work *outptr) {
...
return inptr;
}
и назовите это как:
work_travel = get_work(work_travel, curr_travel);
Или передать указатель на обновляемый объект, например:
int get_work (work **inptr_p, work *outptr) {
work *inptr = *inptr_p;
if (inptr == NULL) {
printf(" No work found...n");
return -1;
} else {
outptr = inptr;
printf(" work found: str: %s|| int: %dn",inptr->str, inptr->i);
inptr = inptr->next;
*inptr_p = inptr;
return 0;
}
}
...
get_work (amp;work_travel, curr_travel);
Комментарии:
1. Затем мне просто нужно будет проверить, возвращает ли функция get_work() значение NUll. И, конечно, я знаю, что использование структуры с именем work — плохая практика, но это всего лишь доказательство концепции