#c #pointers #c99
#c #указатели #c99
Вопрос:
Я пытаюсь создать функции из существующего кода, чтобы сделать его чище, и у меня возникают некоторые проблемы:
Раньше это было:
int foo(char * s, char * t, char ** out) {
int val = strcmp(s, t);
if (val == 0) {
*out = strdup(s);
return 1;
} else {
*out = strdup(t);
return 5;
}
return 0;
}
Теперь у меня есть:
int foo(char * s, char * t, char ** out) {
someFunction(s, t, out);
printf("%s", *out);
return 0;
}
int someFunction(char *s, char * t, char **out) {
int val = strcmp(s, t);
if (val == 0) {
*out = strdup(s);
return 1;
} else {
*out = strdup(t);
return 5;
}
return 0;
}
И я получаю ошибки сегментации, когда пытаюсь выполнить printf. Должна ли какая-то функция ожидать * out? Наверное, я все еще в замешательстве.
Комментарии:
1. На что
someFunction
похоже? Кроме того, это не может быть код, который вы скомпилировали и запустили, поскольку в нем отсутствует имя функции. Пожалуйста, вставьте реальный код (разумеется, выбранный для краткости).2. Также было бы полезно посмотреть, как вы вызываете (в настоящее время безымянную) функцию. В частности, что вы передаете для значений
s
,t
иout
? Полный, компилируемый пример, который воспроизводит ваш segfault, был бы идеальным.3. Я попытался исправить это как можно лучше.
Ответ №1:
Этот код «правильный», если я понимаю ваше намерение. Я предполагаю, что вы делаете что-то вроде
char *s = "foo";
char *t = "bar";
char *out;
foo(s, t, out);
когда вы действительно хотите
char *s = "foo";
char *t = "bar";
char *out;
foo(s, t, amp;out); // Note the amp; which passes the address of a char* to be manipulated
Комментарии:
1. Нет,
foo
это вашеfoo
. Вы куда-то вызываетеfoo
. Ваш вызовfoo
должен быть некорректным (как в моем первом примере), потому что нет ничего неправильного в том, какfoo
выполняется вызовsomeFunction
, или в том, как онsomeFunction
манипулирует*out
.2. Другими словами, вы предоставляете недопустимое значение
char**
дляout
аргументаfoo
. В конечном итоге это приводит к segfault приsomeFunction
попытке записи на недопустимый адрес памяти.3. Итак, даже если foo вызывает someFunction, в конечном итоге out всегда доступен с правильным содержимым?
4. Я не уверен, что вы подразумеваете под «всегда доступным».
out
это указатель на указатель. Вы передаете это изfoo
вsomeFunction
. В том, как вы это делаете, в предоставленном вами коде нет ничего плохого. Это правильный код. Ваш segfault должен означать, что ваша проблема заключается в том, как вы вызываетеfoo
. Однако вы не опубликовали этот код, поэтому он не может быть проанализирован.5. Не будет ли это обычно вызывать ошибку компилятора, поскольку нет явного приведения из
char*
вchar**
? Я бы попытался скомпилировать сgcc -Wall
и посмотреть, не удастся ли скомпилировать в ожидании некоторых неправильных приведений. Обычно я предполагаю, что gcc может предупредить вас без-Wall
опции и просто вывести список ошибок. Однако с-Wall
опцией это предотвратит неправильное приведение указателей, если это действительно то, что происходит.
Ответ №2:
Я бы преобразовал это таким образом:
int foo(char * s, char * t, char ** out) {
int val = strcmp(s, t);
*out = val ? strdup(t) : strdup(s);
return val ? 5 : 1;
}
Комментарии:
1. Хотя это может быть приемлемым способом рефакторинга функции
foo
(хотя я бы не согласился, поскольку она тестируетсяval
дважды), на самом деле это не дает ответа на заданный вопрос.2. Хотя хочу поблагодарить, каждой попытке задать вопрос здесь а) предшествует как минимум полчаса битья головой о стол, а затем следует дзен-подобие благодарности за вновь обретенные знания.