Обрезать начальные и конечные пробелы из строки в C - PullRequest
2 голосов
/ 27 марта 2020

Я искал переполнение стека для помощи по своей функции void strip(char *s) и не нашел подходящего ответа, соответствующего моим требованиям. Каждая реализация, которую я пробовал, приводила к SEGFAULT.

Моя идея состоит в том, чтобы увеличивать указатель на символ s до тех пор, пока не будут использованы все пробелы. Тогда у меня есть указатель на конец строки end. Я уменьшаю этот указатель до тех пор, пока все пустое пространство не будет уничтожено. Я подключил свой код в GDB, чтобы убедиться, что все указывает правильно, что он делает. Однако, когда я пытаюсь отрезать пробел, вставляя нулевой символ, чтобы обозначить конец новой подстроки, я не могу заставить его работать.

СМОТРЕТЬ РЕДАКТИРОВАТЬ:

void strip(char *s) {
  char *end;

  int length = strlen(s);
  end = s + length - 1;

  while (1) {
    if (*s == ' ' || *s == '\t' || *s == '\n') {
      s++;
    } else {
      break;
    }
  }

  while (1) {
    if (*end == ' ' || *end == '\t' || *end == '\n') {
      // *end = '\0'; my current implementation has this uncommented
      end--;
    } else {
      break;
    }
  }
}

int main(void) {
  char *string = "\tHello, World\t";
  strip(string);

  printf("%s\n", string);
}

Насколько я понимаю, по крайней мере, главная функция должна печатать Hello, World\t. с задней вкладкой все еще на месте. Однако консоль выводит \tHello, World\t, как если бы указатель никогда не перемещался.

Вот номер реализации 2. Этот использует два указателя для начала и конца. Затем создает новую строку для s, на которую можно указать. Это также приводит к распечатке \tHello, World\t. GDB, с другой стороны, видит temp как Hello, World.

void strip(char *s) {
  char *start, *end;

  int length = strlen(s);
  end = s + length - 1;

  while (1) {
    if (*start == ' ' || *start == '\t' || *start == '\n') {
      start++;
    } else {
      break;
    }
  }

  while (1) {
    if (*end == ' ' || *end == '\t' || *end == '\n') {
      end--;
    } else {
      break;
    }
  }

  char temp[length];

  int index = 0;

  while (start <= end) {
    temp[index++] = *start;
    start++;
  }

  temp[index] = '\0';

  s = temp;
}

EDIT

void strip(char *s)
{
    char *end;

    int length = strlen(s);
    end = s + length - 1;

    // while a character is a space AND didn't reach the end
    while (s != NULL && isspace(*s))
    {
        s++;
    }

    // While end has not passed ptr s AND is a space
    while (end > s && isspace(*end))
    {
        // replace the whitespace
        *end = '\0';
        end--;
    }
}


int linesff(const char *s, char **lines)
{
    FILE *fp;

    if ((fp = fopen(s, "r")) == NULL)
    {
        printf("Cannot open file: %s\n", s);
        return -1;
    }

    // max buffer size
    char buf[MAX_C];
    int index = 0;

    // while Not EOF
    while (!feof(fp))
    {
        // get a line to put in buf
        fgets(buf, MAX_C, fp);

        // strip buf
        strip(buf);

        // if buf is greater than 1, meaning line has characters left
        if (strlen(buf) > 1)
        {
            // add buf at index
            lines[index] = buf;
            index++;
        }
    }

    // return the count
    return index;
}

Strip - вспомогательная функция для linesff, которая удаляет пробелы. **lines создается следующим образом:

for (int i = 0; i < MAX_L; i++)
    lines[i] = malloc(MAX_C);

Мне все еще не удается изменить buf, чтобы он содержал правильно очищенную строку.

Ответы [ 2 ]

2 голосов
/ 27 марта 2020

Есть некоторые проблемы. temp будет освобожден, как только программа выйдет из функции strip, поэтому s будет указывать на недействительную память. Но s также является локальным для этой функции, поэтому установка его в конце в любом случае не имеет смысла. Вам нужно выделить память в куче, используя, например, malloc, скопировать в нее содержимое temp и вернуть указатель на эту область памяти. Выделенная память в куче будет жить до тех пор, пока вы не освободите их, позвонив им free(...).

Таким образом, это будет работать

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

char* strip(char *s) {
  char *start, *end;

  int length = strlen(s);
  start = s;
  end = s + length - 1;

  while (1) {
    if (*start == ' ' || *start == '\t' || *start == '\n') {
      start++;
    } else {
      break;
    }
  }

  while (1) {
    if (*end == ' ' || *end == '\t' || *end == '\n') {
      end--;
    } else {
      break;
    }
  }

  char temp[length + 1];
  int index = 0;

  while (start <= end) {
    temp[index++] = *start;
    start++;
  }

  temp[index] = '\0';

  char *result = malloc(strlen(temp) + 1);
  if (result == NULL)  // check if malloc failed
    return NULL;

  strcpy(result, temp);
  return result;
}

int main(void) {
  char *string = "\tHello, World\t";
  char *result_string = strip(string);

  // check the return value, if it NULL then something went wrong
  if (result_string != NULL) {
    printf("%s\n", result_string);
    free(result_string);
  } else {
    printf("Error occured\n");
  }
  return 0;
}
1 голос
/ 27 марта 2020
char *string = "\tHello, World\t";

Если вы сделаете это, string будет указателем на постоянную строку, что означает, что вы не можете изменить содержимое строки с помощью *pointer.

Для того, чтобы изменить строку Вы должны выделить строку в стеке или куче, как:

char string[100] = "\tHello, World\t";
...