Обработка указателей внутри нескольких функций в C

#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. Хотя хочу поблагодарить, каждой попытке задать вопрос здесь а) предшествует как минимум полчаса битья головой о стол, а затем следует дзен-подобие благодарности за вновь обретенные знания.