Сборка strcat без библиотеки и без указателей - PullRequest
0 голосов
/ 26 января 2019

Меня попросили собрать из без использования библиотеки и указателей.

Пока у меня это есть, но почему-то это не такt работа:

void strcatO(char a[], char b[])
{
    int i = 0;

    for(i = 0; i < strlen(b); ++i)
    {
        a[strlen(a) + i + 1] = b[i];
    }

    printf("%s", a);
}

Вывод:

a

Ответы [ 4 ]

0 голосов
/ 26 января 2019

Эта строка:

a[strlen(a) + i + 1] = b[i];

пишет символы на одну позицию дальше, чем вы хотите.

При вызове в вашем примере вашей программе передаются a и b со следующим содержимым:

a[0] = 'e'
a[1] = 'g'
a[2] = 'g'
a[3] = 0

b[0] = 's'
b[1] = 'a'
b[2] = 'm'
b[3] = 'p'
b[4] = 'l'
b[5] = 'e'
b[6] = 0

Вы хотите получить такой результат:

a[0] = 'e'
a[1] = 'g'
a[2] = 'g'
a[3] = 's'
a[4] = 'a'
a[5] = 'm'
a[6] = 'p'
a[7] = 'l'
a[8] = 'e'
a[9] = 0

Однако, поскольку ваш код записывает в a[strlen(a) + i + 1], он записывает первый символ в a[strlen(a) + 0 + 1], то есть a[4]. Вы хотите это в a[3]. Вы можете изменить strlen(a) + i + 1 на strlen(a) + i, но тогда, когда вы напишите первый символ, вы перезапишете нулевой завершающий символ, и strlen больше не будет работать, чтобы найти длину. Чтобы это исправить, вы можете запомнить длину a перед входом в цикл. Рассмотрим этот код:

int i = 0;
int LengthOfA = strlen(a);
for (i = 0; i < strlen(b); ++i)
{
    a[LengthOfA + i] = b[i];
}

Это запишет символы в правильное место.

Тем не менее, он не ставит нулевой завершающий символ в конце a. Для этого мы можем поставить еще один оператор после цикла:

a[LengthOfA + i] = 0;

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

Во-первых, вместо использования int для длин и индексов мы можем использовать size_t. В C ширина int является гибкой, и size_t предоставляется как хороший тип для использования при работе с размерами объектов. Чтобы использовать его, сначала используйте #include <stddef.h>, чтобы получить его определение. Тогда ваш код может быть:

size_t i = 0;
size_t LengthOfA = strlen(a);
for (i = 0; i < strlen(b); ++i)
{
    a[LengthOfA + i] = b[i];
}
a[LengthOfA + i] = 0;

Во-вторых, ваш код номинально вычисляет strlen(b) на каждой итерации. Это расточительно. Предпочтительно рассчитать длину один раз и запомнить ее:

size_t i = 0;
size_t LengthOfA = strlen(a);
size_t LengthOfB = strlen(b);
for (i = 0; i < LengthOfB; ++i)
{
    a[LengthOfA + i] = b[i];
}
a[LengthOfA + i] = 0;
0 голосов
/ 26 января 2019

из ваших проблем вы постоянно вычисляете strlen без всякой надежды на оптимизацию компилятора, вы можете сделать это:

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

void strcatO(char a[], char b[])
{
   size_t i = strlen(a);
   size_t j;

    for (j = 0; b[j] != 0; ++j)
    {
        a[i++] = b[j];
    }

    a[i] = 0;

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

int main()
{
  char a[20] = "aze";
  char b[] = "rtyu";
  strcatO(a,b);
  return 0;
}

Выполнение:

azertyu

Обратите внимание, что char a[] для параметра в точности равно char *, без указателей - ложь; -)


и указывает на проблемы в вашем коде, как этого требует Эрик Постпишиль:

  • a[strlen(a) + i + 1] записывает 1 символ после правильной позиции, должно быть a[strlen(a) + 1] = 0; a[strlen(a)] = b[j];.В некотором смысле это шанс, иначе вы напишете более далеко после конца, потому что strlen не будет возвращать начальную длину a , но неопределенное значение из-за возможного пропуска нулевого символа востаток a
  • после копирования, который вы пропустили, чтобы добавить нулевой символ
0 голосов
/ 26 января 2019

каким-то образом это не работает

a[strlen(a) + i + 1] = b[i]; добавляет символы после a * нулевой символ .

void strcatO(char a[], char b[]) {
    int i = 0;
    for(i = 0; i < strlen(b); ++i) {
      a[strlen(a) + i + 1] = b[i];  // Oops: appending position is off-by-one
    }
    printf("%s", a);
}

strcatO("ab", "cd") будет заполнен a как 'a', 'b', '\0', 'c', 'd'.

Печать с печатью printf("%s", a); только 'a', 'b'.


Чтобы исправить, код должен добавляться в правильном положении, но это перезаписывает исходный a нулевой символ .Таким образом, вызовы strlen(a) являются плохими.

Вместо этого и повышают эффективность , не звоните strlen() повторно.

void strcatO(char a[], const char b[]) {
  size_t ai = 0;
  while (a[ai]) {       // go to end of a
    ai++;
  }

  size_t bi = 0;
  while (b[bi]) {        // while not at the end of b ...
    a[ai++] = b[bi++];
  }

  a[ai] = '\0';
  printf("<%s>", a);
}

Подробная информация отонкие улучшения:

const в const char b[] подразумевает b ссылки на данные, которые эта функция не должна пытаться изменить.Это 1) позволяет этой функции объединять b, если это const char [] 2) Позволяет оптимизации, которые слабый компилятор может не видеть.

size_t лучше, чем int для long строки, которые могут быть длиннее INT_MAX.size_t - это тип «правильного размера» для длины строки и размера массива.У OP (Original Poster) было «без использования библиотеки», и size_t из библиотеки, поэтому код мог использовать unsigned или лучше unsigned long в качестве альтернативы.

0 голосов
/ 26 января 2019

Вы не перезаписываете первую строку null (\0) терминатор

    a[strlen(a) + i + 1] = b[i];

должно быть

int len = strlen(a);

for(i = 0; i < strlen(b); ++i)
{
    a[len + i] = b[i];
}
a[len+i] = '\0'; //Finally null terminate the new string.
...