Как я могу реализовать функцию для объединения с символом *, а не с массивом символов?

#c #concatenation

#c #конкатенация

Вопрос:

Как я могу реализовать функцию, которая будет объединять что-то с символом * (не с массивом символов)? Пример того, что я хочу:

 #include <stdio.h>
#include <string.h>

int main() {
  char* current_line;
  char temp[1];
  sprintf(temp, "%c", 'A');
  // This causes a seg fault. I of course don't want that, so how do I get this to work properly?
  strcat(current_line, temp);
  return 0;
}
 

Как я могу исправить это, чтобы работать должным образом (и, пожалуйста, скажите мне, нужно ли мне что-нибудь добавить к моему вопросу или указать мне правильное направление, потому что я ничего не смог найти)?

Редактировать: я сделал это, но это приводит к ошибкам

 char* charpointercat(char* mystr, char* toconcat) {
  char ret[strlen(mystr)   1];
  for(int i = 0; mystr[i] != ''; i  ) {
    ret[i] = mystr[i];
  }
  return ret;
}
 

Комментарии:

1. Что вы подразумеваете под «объединением чего-либо с символом *»? Где вы ожидаете, что результат будет сохранен?

2. Результат будет сохранен в символе*

3. Вы не можете сохранить строку в a char* . A char* может содержать только указатель на символ. Что вы можете сделать, так это создать a char * , который будет указывать на первый символ в куске памяти, представляющем строку. Вам нужно как-то выделить эту память где-то, что почти наверняка потребует создания массива.

4. Ну, тогда как это char* a = "Hello, world!" работает?

5. @Dock: в примере вашего предыдущего комментария строковый литерал "Hello, world!" хранится в области памяти, доступной только для чтения , которая загружалась из вашего исполняемого файла. Ваша строка кода приведет a к указанию на эту ячейку памяти, доступную только для чтения. Однако для того, что вы хотите сделать, вам нужна память, в которую можно записать.

Ответ №1:

У вас 3 проблемы:

  1. Вы вообще не выделяете память для current_line !
  2. Вы не выделяете достаточно памяти для temp .
  3. Вы возвращаете указатель на локальную переменную из charpointercat .

Первый должен быть очевидным и был объяснен в комментариях:
char *current_line содержит только указатель на некоторые байты, но вам нужно выделить фактические байты, если вы хотите сохранить что-то с помощью функции, подобной stracat .

Для второго, обратите внимание, что для этого sprintf(temp, "%c", 'A'); требуется, по крайней мере char temp[2] , поскольку он будет использовать один байт для «A» и один байт для завершения нулевого символа.

Поскольку sprintf он не знает, насколько велик temp , он записывает за его пределы, и именно так вы получаете ошибку segfault.

Что касается вашего charpointercat , когда функция завершается, ret больше не существует.

Чтобы быть более точным:
массив в C представлен указателем (адресом памяти) его первого элемента (ячейки).

Таким образом, строка return ret; возвращает не копию всех байтов, ret а только указатель на первый байт.

Но этот адрес памяти действителен только внутри charpointercat функции.
Как только вы пытаетесь использовать его снаружи, это «неопределенное поведение», поэтому может произойти что угодно, включая segfault.

Есть два способа исправить это:

  1. Узнайте, как использовать malloc и выделять память в куче.
  2. Передайте функции третий массив, чтобы она могла сохранить там результат (так же, как вы делаете с sprintf ).

Ответ №2:

Из первого опубликованного вами кода кажется, что вы хотите объединить символ с концом строки… Этот код вернет новую строку, состоящую из первой, за которой следует вторая, параметр не изменится.

 char* charpointercat(char* mystr, char toconcat) {
    char *ret = (char*) malloc(sizeof(char)*(strlen(mystr)   2));
    int i;
    for(i = 0; mystr[i] != ''; i  ) {
        ret[i] = mystr[i];
     }
     ret[i] = toconcat;
     ret[i   1] = '';
     return ret;
 }
 

Ответ №3:

Это должно сработать:

 char* charpointercat(char* mystr, char* toconcat) {
  size_t l1,l2;
  //Get lengths of strings
  l1=strlen(mystr);
  l2=strlen(toconcat);
  //Allocate enough memory for both
  char * ret=malloc(l1 l2 1);
  strcpy(ret,mystr);
  strcat(ret,toconcat);
  //Add null terminator
  ret[l1 l2]='';
  return ret;
}

int main(){
  char * p=charpointercat("Hello","World");
  printf("%s",p);
  //Free the memory
  free(p); 
}
 

Комментарии:

1. Почему бы просто не использовать strcpy вместо первого цикла и strcat вместо второго цикла?

2. Это не будет вести себя так, как вы ожидаете, если l1 , l2 , или их сумма плюс единица больше, INT_MAX чем . Возможно, вы хотите использовать size_t ?

3. Да, вы правы в том, что ваш предыдущий код был, в принципе, более эффективным, потому strcat что нужно снова пройти по первой строке, чтобы найти конец. Кроме того, в вашем предыдущем коде был записан только один завершающий символ null, так что это также было более эффективно. Итак, на самом деле у вас была веская причина не использовать функции strcpy и strcat , даже если в этом случае, вероятно, лучше использовать эти две функции, потому что простота, вероятно, важнее эффективности для вопроса. Однако в вашем текущем решении строка ret[l1 l2]=''; больше не нужна.

4. Причина strcpy , по которой и strcat являются более эффективными, чем ваше первое решение, несмотря на то, что ваше решение в принципе более эффективно, вероятно, заключается в том, что эти две функции сильно оптимизированы на уровне языка ассемблера. Вы запускали свой тест с активными полными оптимизациями компилятора ( -O3 на большинстве компиляторов)?

5. @EvanHendler: Обратите внимание, что флаг не -03 , но -O3 , то есть буква O, а не число. В своем последнем комментарии вы написали число. Это не сработает, если вы используете число.