Когда я использую функцию "strcat", это вызывает ошибку сегментации... почему? [дубликат]

avatar
weichih25
9 августа 2021 в 01:01
131
2
-3

Я хочу объединить две строки.
Сначала я попробовал этот, все в порядке.

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

int main(int argc, const char * argv[])
{
   char a[100] = "0";
   char b[100] = "1";
   //char *a = "0";
   //char *b = "1";

   printf("%s\n", a);
   printf("%s\n", b);
   strcat(a,b);
   printf("%s\n", a);

   return 0;
}

///////////////////////////
0
1
01

Но второй вызвал проблему. Не могу понять, где не правильно.

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

int main(int argc, const char * argv[])
{
   //char a[100] = "0";
   //char b[100] = "1";
   char *a = "0";
   char *b = "1";

   printf("%s\n", a);
   printf("%s\n", b);
   strcat(a,b);
   printf("%s\n", a);

   return 0;
}
///////////////////////////
0
1
Segmentation fault

Понятия не имею, почему... Кто-нибудь может объяснить... пожалуйста?

Источник
Nate Eldredge
9 августа 2021 в 01:04
0

char *a = "0"; устанавливает a для указания на строковый литерал, который (концептуально) находится в постоянной памяти. Попытка изменить эту область памяти вызывает неопределенное поведение - в вашем случае ошибка сегментации.

Nate Eldredge
9 августа 2021 в 01:06
0

Строки на самом деле не являются первоклассными объектами в C. Вы должны думать о них как о массивах и понимать операции с ними с точки зрения того, что происходит с отдельными символами в этом массиве. Понимание указателей является важной частью этого.

Andreas Wenzel
9 августа 2021 в 01:25
0

@kaylum: обратите внимание, что предлагаемый вами дубликат помечен как C++, а не C. По крайней мере, один из ответов на этот вопрос содержит информацию, не относящуюся к C. Поэтому я не уверен, уместно ли помечать его как дубликат для вопрос С. Однако, кроме этого момента, вопрос кажется точным дубликатом.

Ответы (2)

avatar
NghtCtrL
9 августа 2021 в 01:16
2

Если вы читали Руководство программиста Linux о strcat(), там представлен прототип функции в виде:

char *strcat(char *restrict dest, const char *restrict src) 

Затем поясняется, что это значит:

Функция strcat() добавляет строку src к строке назначения, перезапись завершающего нулевого байта ('\0') в конце адресата и затем добавляет завершающий нулевой байт.

Ключ здесь "добавляет", что означает управление строкой. Однако в C есть два способа хранения строк:

Вот один из способов:

char *str = "Hello, World!";

А вот еще один способ:

char str[] = "Hello, World!";

Разница здесь в том, что первый хранит строку "Hello, World!" в постоянной памяти, а str — указатель на это место; в то время как последний сохраняет строку в доступной для записи памяти.

В C вы не можете манипулировать тем, что хранится в постоянной памяти, и поэтому ваш код не работает.

weichih25
9 августа 2021 в 01:59
0

char *a = "aaa"; printf("%s\n", a); a = "bbb"; printf("%s\n", a); Но почему я могу манипулировать значением здесь? Я не понимаю, что означает "постоянная память".

Andreas Wenzel
9 августа 2021 в 02:01
0

@ weichih25: В этом коде вы не меняете сам строковый литерал. Вместо этого вы просто указываете указатель на другой строковый литерал, то есть на другое место в памяти.

NghtCtrL
9 августа 2021 в 02:10
0

@ weichih25 weichih25 «Память только для чтения» означает, что вы не можете изменить содержимое того, что вы там сохранили: это все равно, что писать что-то перманентным маркером. Когда вы скомпилируете код, который вы написали в комментарии, C сначала 1) выделит постоянную память для строки «aaa», затем 2) сохранит адрес этой строки в переменной-указателе a (как сказал Андреас Венцель). Обратите внимание, что «aaa» доступна только для чтения, а не переменная-указатель a. Вот почему вы можете делать такие вещи, как a = "bbb" (но тогда адрес "aaa" будет потерян навсегда).

weichih25
10 августа 2021 в 07:19
0

@AndreasWenzel Понятно, спасибо

avatar
Andreas Wenzel
9 августа 2021 в 01:05
0

Линии

char a[100] = "0";
char b[100] = "1";

выделить два массива длиной 100 каждый и инициализировать массивы так, чтобы они содержали строки "0" и "1".

Тем не менее, строки

char *a = "0";
char *b = "1";

создайте два указателя, каждый из которых указывает на строковый литерал, который является строкой, находящейся в постоянной памяти.

Поэтому попытка записи в одну из этих строк с использованием strcat приводит к неопределенному поведению (в вашем случае ошибка сегментации).

Даже если строковые литералы не расположены в постоянной памяти, ваш код, вероятно, все равно не будет работать, потому что при использовании strcat вы также должны убедиться, что буфер памяти целевой строки достаточно велик, чтобы содержать обе строки.