Я пытаюсь решить часть кода, который мне прислал друг. Он тренируется с указателями и пытается перевернуть строку, используя их.
Это должна быть довольно простая задача, но здесь просто пробел в моих знаниях. Мне удалось успешно создать циклы for, которые правильно перебирают строку, используя i
и j
в качестве управляющих переменных. Я также смог распечатать символы, которые нужно поменять местами.
Единственная проблема заключается в том, что закомментированная строка кода в цикле for. Предполагается, что он меняет местами два значения, но выдает ошибку, и я не понимаю, почему.
#include <stdio.h>
int length(char *p);
void reverse(char *);
int main() {
char *p = "Computer";
reverse(p);
}
int length(char *p) {
int i;
for (i = 0; *(p + i) != '\0'; i++);
return i;
}
void reverse(char *p) {
int l, i;
char t;
for (l = 0; *(p + l) != '\0'; l++);
int len = l;
int temp;
for (i = 0; i < l; i++, l--) {
t = *(p + i);
printf("i-th element - %c\n", t);
printf("j-th element - %c\n", *(p + len - 1 - i));
*(p + i) = *(p + len - 1 - i); // crash
}
puts(p);
}
Я даже не уверен, что их можно поменять местами таким образом. Я бы выбрал подход t = p[i]; p[i] = p[i + 1]...
. Если кто-нибудь может исправить и объяснить это и драму, связанную с указателем, это было бы здорово.
Зачем использовать простую и многословную *(p + i)
нотацию вместо более простой p[i]
нотации? Использование индексов имеет дело с указателями так же, как и явная, подробная альтернатива.
Во-первых, вы не должны пытаться модифицировать строковые литералы.
Вы должны использовать (модифицируемый) массив:
char p[] = "Computer";
вместо
char *p = "Computer";
Во-вторых, вам понадобится
*(p + len - 1 - i) = t;
после
*(p + i) = *(p + len - 1 - i);
для завершения обмена.
Ух ты. Я не могу в это поверить. Я просто должен был изменить это. char p[] = "Компьютер";. Я уже знал, как выполнить обмен, это было просто для проверки.
Не могли бы вы объяснить причину и разницу между двумя ([] и *)? У меня проблемы с пониманием указателей.
@StormClaw c - В чем разница между char s[] и char *s? - Переполнение стека
Для начала вы не можете изменить строковый литерал
char *p = "Computer";
любая попытка изменить строковый литерал приводит к неопределенному поведению.
Поэтому вместо указателя на строковый литерал объявите массив символов, например
char s[] = "Computer";
Более того, ваша функция reverse
не использует функцию length
и фактически не переворачивает строку.
Эта петля
for (i = 0; i < l; i++, l--) {
использует две вспомогательные переменные в качестве индексов.
Функция reverse
не должна ничего выводить. Что он должен сделать, так это отменить переданную строку. Именно вызывающая функция решает, выводить ли перевернутую строку или использовать ее для других целей.
Функции length
и reverse
могут быть объявлены и определены с использованием только указателей следующим образом.
size_t length( const char *s )
{
const char *p = s;
while ( *p ) ++p;
return p - s;
}
и
char * reverse( char *s )
{
if ( *s )
{
for ( char *p = s, *q = s + length( s ); p < --q; ++p )
{
char c = *p;
*p = *q;
*q = c;
}
}
return s;
}
Функция reverse может быть вызвана как
int main( void )
{
char s[] = "Computer";
puts( s );
puts( reverse( s ) );
}
Вот демонстрационная программа.
#include <stdio.h>
size_t length( const char *s )
{
const char *p = s;
while ( *p ) ++p;
return p - s;
}
char * reverse( char *s )
{
if ( *s )
{
for ( char *p = s, *q = s + length( s ); p < --q; ++p )
{
char c = *p;
*p = *q;
*q = c;
}
}
return s;
}
int main( void )
{
char s[] = "Computer";
puts( s );
puts( reverse( s ) );
}
Его вывод
Computer
retupmoC
Как видите, в обеих функциях нет ни одной переменной, используемой в качестве индекса. Функции используют только указатели.
Использование пуантов требует некоторой осторожности, иначе вы везде получите «ошибку сегментации». Но давайте сделаем это. Техника обращения строки, которую я использую, заключается в том, чтобы сначала позиционировать один указатель на начало строки, а другой указатель на конец строки; и продвигайте своп, пока они достигают середины строки (таким образом я сократил обработку до половины), проверьте этот код
/* reverses a string
* !!! this function modifies input string !!!
*/
char *reverse(char *s)
{
char *h, *t, c; /* h)ead, t)ail and a temporary c */
int len = 0;
/* positioning the pointers at beginning and end of string s */
len = length(s);
h = (char*)&s[0];
t = (char*)&s[len - 1];
for (int i = 0; i < (len / 2); i++)
{
/* swap chars */
c = *h;
*h = *t;
*t = c;
/* increase h pointer, decrease t pointer */
h++;
t--;
}
return s;
}
Чистые указатели... в любой форме при замене *h и *t вы не можете уйти от временного хранилища ( c );
Имейте в виду, что входная строка должна быть объявлена как char name[], иначе sigsegv следует за вами!
Если вы хотите сохранить строку для последующей печати непосредственно в stdout
, вы можете сделать это:
char * reverse(char * I){
int i,l;
char * O;
l=strlen(I);
O=malloc(l+1);
for(i=1;i<=l;i++)O[i-1]=I[l-i];
O[l]='\0';
return O;
}
int main(){
char * p=reverse("Computer");
printf("%s",p);
free(p);
}
Какую ошибку выдает?