Эта строка:
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;
person
Eric Postpischil
schedule
26.01.2019
char a[]
, компилятор действительно обрабатывает его какchar *a
. Так что нет, вы не делаете это без указателей. - person Some programmer dude   schedule 26.01.2019strlen()
это из библиотеки. Иa
, иb
являются действительно указателями, даже если их объявление выглядит как массивы. На самом деле, если ваш учитель говорит вам, что это не так, попросите его объяснить, почемуsizeof( a )
в вашемstrcat()
всегда будет равноsizeof( char * )
, независимо от того, насколько велик массив в вызове Функция есть. В итоге, поскольку любой массив, который вы используете в качестве аргумента для вызова функции, выродится в указатель, ваш учитель оказал своим ученикам медвежью услугу, сформулировав задачу таким образом. Ответ в том, что это невозможно сделать, все, что я могу сделать, это написать это без*
. - person DevSolar   schedule 26.01.2019void f(int arr[]);
иvoid f(int *arr);
— это одно и то же; они взаимозаменяемы. Дажеvoid f(int arr[5]);
не имеет значения; индекс игнорируется. Если вас смущают семантические и условные особенности C, вы не одиноки. - person Peter - Reinstate Monica   schedule 26.01.2019b
равнаN
. затемfor(i = 0; i < strlen(b); ++i) { ... }
звонит операторуstrlen(N)
N раз. Каждый вызов работает внизb
, чтобы найти длину илиN
операций. Будучи кодом OP, компилятор, вероятно, не распознает эту неэффективность, а затем сделает этот кодO(N*N)
- очень медленным. Вместо этого вызовитеstrlen(b)
перед циклом или просто используйтеfor(i = 0; b[i]; ++i)
. - person chux - Reinstate Monica   schedule 26.01.2019void f(int arr[5]);
неясно, игнорируется ли длина массива. Некоторые компиляторы оценивают выражение размера массива (после чего значение отбрасывается). Например, с Apple LLVM 10.0.0 clang-1000.11.45.5void f(int arr[printf("Hello, world.\n")]) {} int main(void) { f(0); }
печатает «Привет, мир». - person Eric Postpischil   schedule 26.01.2019