работа со строками в c- расширение, замена, хранение и печать строк - PullRequest
0 голосов
/ 01 июня 2018

У меня есть простая программа на C, которая должна расширять строку FX в соответствии со следующими правилами:

X -> X+YF+
Y-> -FX-Y

Программа выглядит следующим образом:

#include <stdio.h>
void expandOnce( )
{
     char* s = (char*)malloc(sizeof(char)*100);
     int i=0;
     char str[]="FX";
     while(str[i]!='\0')
     {
           if(str[i]=='X')
           {
               s[i]="X+YF+";
           }
             if(str[i]=='Y')
           {
               s[i]="-FX-Y";
           }
           i++;
     }
          printf("%s",s);
}


void expandNtimes (int n)
{

for (int i =0; i < n; i++){
expandOnce();
}

}
int main(){
   expandNtimes(2);
    return 0;
}

Еслипрограмма выполняется правильно, она должна распечатать:

  FX+YF++-FX-YF+

Это после 2 расширений FX с использованием вышеуказанных правил.Вопросы: 1. Как вы можете сделать это без распечатки бреда?2. Как я могу вернуть расширенный массив из expandNtimes () и expandOnce (), чтобы я мог, например, использовать его в основной функции?

Я пробую это, но продолжаю получать ошибки памяти.

После ваших предложений я внес следующие изменения:

#include <stdio.h>
#include <string.h>
#define NTIMES  2
#define MAXC  100

void expandOnce( )
{
    char s[MAXC];
     int i=0;
     s[0]='F';
     s[1]='X';

     while(s[i]!='\0')
     {
    if(s[i]=='X'){
    //shift all letters to the right by 5 steps
        for (i; i < MAXC; i++){ //warning: statement with no effect (Wunused value)
            s[i + 5]= s[i];
            if(s[i]=='\0'){
            break;}
                  }
    //Fill in the expansion
        s[i]='X';
        s[i+1] ='+';
        s[i+2] ='Y';
        s[i+3]='F';
        s[i+4] ='+';
    }
  if(s[i]=='Y'){
  //shift all letters to the right by 5 steps
        for (i; i < MAXC; i++){ //warning: statement with no effect (Wunused value)
            s[i + 5]=s[i];
            if(s[i]=='\0'){
            break;}
                }
    //Fill in the expansion
        s[i]='-';
        s[i+1] ='F';
        s[i+2] ='X';
        s[i+3]='-';
        s[i+4] ='Y';
    }
             i++;
     }
          printf("%s\n",s);
           printf("Me\n");
}


void expandNtimes (int n)
{

for (int i =0; i < n; i++){
expandOnce();
}

}
int main(){
expandOnce();
expandNtimes(NTIMES);
return 0;
}

Оба моих цикла for имеют предупреждение warning: statement with no effect (Wunused value), которое я не понимаю.Наконец, я получаю эту ошибку:

Segmentation fault (core dumped)

Разрешено ли делать цикл for внутри цикла while?

Ответы [ 2 ]

0 голосов
/ 01 июня 2018

О, Боже ... У вас есть полный список "вы не можете сделать это ..." в своем коде.

Для начала нет необходимости разыгрывать возврат 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
0 голосов
/ 01 июня 2018

Вы получаете ошибки памяти, потому что вы пытаетесь записать в память, где вы ничего не должны делать. Если вы хотите добавить строку, вы должны использовать функцию strcat ()!Строка s [i] = "X + YF +";никогда не скомпилируется, потому что вы пытаетесь написать несколько символов в месте, где разрешен только один символ.я думаю, что лучше делать s глобальными и добавлять символы один за другим к strcat, пока вы не создадите строку.Вы можете получить доступ к глобальным переменным в main.Then вывести строку s.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...