О, Боже ... У вас есть полный список "вы не можете сделать это ..." в своем коде.
Для начала нет необходимости разыгрывать возврат malloc
это не нужно.См .: Нужно ли приводить результат malloc? .
char *s = malloc (sizeof *s * 100);
- это все, что нужно (примечание: если вы всегда используете sizeof dereference_pointer
, у вас всегда будет правильный размер шрифта.
Это поднимает другую точку, если вам нужны константы #define
одна (или более) или используйте глобальный enum
для выполнения той же вещи, например
#define NTIMES 2
#define MAXC 100
или
enum { NTIMES = 2, MAXC = 100 };
Затем вы можете использовать их, например,
char *s = malloc (sizeof *s * MAXC);
и
expandNtimes(NTIMES);
Определив константы, вы получите одно удобное место в верхней части кода длявносите изменения в случае необходимости в будущем, и вам не придется выбирать при каждом выделении или вызове функции изменения всех ваших жестко закодированных магических чисел .
утечка памяти
Вы выделяете s
в expandOnce
, но никогда free
s
и не возвращаете указатель, чтобы он мог быть позже освобожден в main()
(или любой другой вызывающей функции).
Вы должны включить free (s);
после printf("%s",s);
(который также должен включать newline
, чтобы предотвратить выход несколькихработает вместе, и ваша программа совместима с POSIX - выводит окончательный '\n'
), например, printf("%s\n",s);
Более того, «Почему вы все равно динамически выделяете?» Просто используйтефиксированный буфер, вы не пытаетесь его вернуть.Просто используйте:
char s[MAXC] = "";
s
неинициализирован, и вы оставляете s[0]
Неинициализированным
s[i]="X+YF+";
и s[i]="-FX-Y";
записывает 4 символа в s
из индекса 1
.s[0]
никогда не инициализируется, поэтому любая последующая попытка чтения из s
вызывает Неопределенное поведение .Вы не можете просто назначить указатель на строковый литерал "X+YF+";
на символ s[i]
- ваш компилятор должен выкрикивать предупреждения и ошибки на вас .
Youможно скопировать литерал в s
с помощью:
strcpy (s, "X+YF+");
или вы можете просто циклически повторять копирование по ходу, например,
int i;
for (i = 0; str[i]; i++) /* loop over each char in str */
s[i] = str[i]; /* assign to s */
s[i] = 0; /* don't forget to nul-terminate s */
Компилировать с включенными предупреждениями
Всегда компилировать с включенными предупреждениями , а не принимать код, пока он не скомпилируется без предупреждения .Чтобы включить предупреждения, добавьте -Wall -Wextra
в строку компиляции gcc
или clang
.(добавьте -pedantic
для нескольких дополнительных предупреждений).Для clang
вместо этого вы можете использовать -Weverything
.Для VS (cl.exe
при windoze) добавьте /W3
(или используйте /Wall
для включения всех предупреждений).
Прочитайте и поймите каждое предупреждение.Они будут определять любые проблемы и точную линию, на которой они возникают.Вы можете узнать как можно больше о кодировании, просто прислушиваясь к тому, что говорит ваш компилятор, как вы можете из большинства руководств.
Используйте эти предложения, а затем отредактируйте свой вопрос (или задайте новый), если у вас естьдальнейшие проблемы.
Дополнительные комментарии после редактирования
Gakuo, очевидно, вы все еще пытаетесь разобраться с обработкой массива строк / символов, чтобы сделатьрасширения работают.Как я упоминал в комментариях, всякий раз, когда у вас возникает проблема, подобная этой, не поднимайте клавиатуру и не начинайте отрываться в надежде, что вы сможете повозиться достаточно долго, чтобы божественное вмешательство каким-то образом привело вас к решению (этоне будет ...).
Вместо этого сначала возьмите лист бумаги размером 8 1/2 x 11 (миллиметровка хорошо работает) и запишите исходную строку, а затем спланируйте каждый шаг, необходимый для перехода от исходной строки к финальной.нужная вам строка (не забудьте также указать '\0'
в вашем макете)
Например, вы можете начать с вашей исходной строки:
+---+---+---+
| F | X |\0 |
+---+---+---+
Следующий шаг будетчтобы представить сдвиг, чтобы освободить место для вашего расширения (вы оставляете оригинальный символ на месте, так как вы просто перезапишите его):
+---+---+---+---+---+---+---+
| F | X | | | | |\0 |
+---+---+---+---+---+---+---+
Теперь нужно скопировать "X+YF+"
в положение'X'
в результате:
+---+---+---+---+---+---+---+
| F | X | + | Y | F | + |\0 |
+---+---+---+---+---+---+---+
Затем просто повторите этот процесс, пока вы полностью не расширились N раз.Как вы это сделаете, вы сможете определить шаблон для расширения в N раз - и тогда пришло время взять клавиатуру.
Для вашего случая, вместо того, чтобы вручную все зацикливаться, используйтеmemmove
и memcpy
, чтобы помочь сдвигать и копировать в строке.(вы можете вручную сдвигать и копировать с помощью цикла - до тех пор, пока вы можете найти больше букв для вашей переменной цикла, чем просто 'i'
).Позволяя функциям памяти помочь, вы можете сделать что-то вроде:
( примечание: отредактировано с учетом изменения длины s
в expandonce()
)
#include <stdio.h>
#include <string.h>
#define NTIMES 2
#define MAXC 100
#define SDEF "FX" /* string (default) */
#define XEXP "X+YF+" /* X expansion */
#define YEXP "-FX-Y" /* Y expansion */
/* returns pointer to 1-past last expansion on success, NULL otherwise */
char *expandonce (char *s)
{
char *p = s,
*expanded = NULL;
size_t lxexp = strlen (XEXP),
lyexp = strlen (YEXP);
while (*p) {
if (*p == 'X') { /* handle 'X' found */
size_t lens = strlen (s); /* get new length of s */
if (MAXC > lens + lxexp) { /* room to expand? */
size_t lenp = strlen (p); /* total to shift */
/* shift chars to right of 'X' by lxexp-1 including '\0' */
memmove (p + lxexp, p + 1, lenp + lxexp - 1);
memcpy (p, XEXP, lxexp); /* copy expansion */
p += lxexp; /* add offset */
expanded = p; /* set return */
}
}
else if (*p == 'Y') { /* handle 'Y' found */
size_t lens = strlen (s); /* same for 'Y' */
if (MAXC > lens + lyexp) {
size_t lenp = strlen (p);
memmove (p + lyexp, p + 1, lenp + lyexp - 1);
memcpy (p, YEXP, lyexp);
p += lyexp;
expanded = p;
}
}
else /* handle all other chars */
p++;
}
return expanded;
}
/* returns number of successful expansion loops */
int expandntimes (char *s, int n)
{
int i = 0;
char *p = s;
for (i = 0; i < n; i++)
if ((p = expandonce (s)) == NULL)
break;
return i;
}
int main (int argc, char **argv) {
char str[MAXC] = "";
int n = 0;
if (argc > 1 && strlen (argv[1]) < MAXC - 1)
strcpy (str, argv[1]);
else
strcpy (str, SDEF);
printf ("string: %s\nX_exp : %s\nY_exp : %s\n\n", str, XEXP, YEXP);
n = expandntimes (str, NTIMES);
if (n == 0) {
fputs ("error: no expansions possible.\n", stderr);
return 1;
}
printf ("%d expansions => %s\n", n, str);
return 0;
}
(примечание: это минимальный пример - вы должны убедиться, что все угловые случаи покрыты при прохождении вашего проекта)
Пример Использование / Вывод
Ваш пример:
$ ./bin/expand2 "FX"
string: FX
X_exp : X+YF+
Y_exp : -FX-Y
2 expansions => FX+YF++-FX-YF+
Немного другая строка:
$ ./bin/expand2 "XY"
string: XY
X_exp : X+YF+
Y_exp : -FX-Y
2 expansions => X+YF++-FX-YF+-FX+YF+--FX-Y