Member 13013165 Ответов: 2

Почему следующее назначение указателя не выполняется?


При кодировании обратной функции в K&R я попытался назначить де-ссылочный указатель (s1) другому де-ссылочному указателю (s2). Я проверил (с большим количеством printf и putchar), что *s1 действительно содержит нужный мне символ, но в массиве, который S2 указывает на изменения символа. Почему это происходит? Спасибо!

Что я уже пробовал:

void reverse(char *s1){
	char a[100];
	char *s2;
	int i=0;
	s2=&a[0];
	while(*s1!='\0'){
		s1++;
		i++;		
	}
	s1--;
	i--;
	while(i>=0){
		*s2=*s1;
	        s2++;
		s1--;
		i--;
	}		
}

2 Ответов

Рейтинг:
2

Patrice T

Чтобы помочь вам понять программу, используйте отладчик, он покажет вам, что именно она делает. Возможно, вам придется переключиться на уровень машинного кода, чтобы увидеть, как компилируется код на языке Си.
-----
Когда вы не понимаете, что делает ваш код или почему он делает то, что делает, ответ таков: отладчик.
Используйте отладчик, чтобы увидеть, что делает ваш код. Просто установите точку останова и посмотрите, как работает ваш код, отладчик позволяет вам выполнять строки 1 на 1 и проверять переменные по мере их выполнения, это невероятный инструмент обучения.

Отладчик-Википедия, свободная энциклопедия[^]
Освоение отладки в Visual Studio 2010 - руководство для начинающих[^]

Отладчик здесь для того, чтобы показать вам, что делает ваш код, и ваша задача-сравнить его с тем, что он должен делать.
В отладчике нет никакой магии, он не находит ошибок, он просто помогает вам. Когда код не делает того, что ожидается, вы близки к ошибке.


Рейтинг:
19

OriginalGriff

Если вы попробуете:

void reverse(char *s1){
	char a[100];
	char *s2;
	int i=0;
	s2=&a[0];
	while(*s1!='\0'){
		s1++;
		i++;		
	}
	s1--;
	i--;
	while(i>=0){
		*s2=*s1;
	        s2++;
		s1--;
		i--;
	}
	printf("%s\n", a);
}



int main()
{
    char s[] = "Hello World!";
    printf("%s\n", s);
    reverse(s);
    return 0;
}
Тогда вы получите результат:
Hello World!                                                                                                                   
!dlroW olleH

Но... это, вероятно, больше по счастливой случайности, чем по здравому смыслу. Проблема в том, что вы не копируете символ окончания строки '\0' из вашего ввода в ваш вывод, как это легко доказать, "предварительно заполнив" массив идентифицируемым мусором:
char *s2;
	int i=0;
	for (i = 0; i < 100; i++)a[i] = 'X';
	i = 0;

Теперь когда вы печатаете вы получаете:
Hello World!                                                                                                                   
!dlroW olleHXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX����l7n��

Потому что в выходной строке нет ничего, что указывало бы printf, когда нужно остановиться!
Либо установите null в конце перевернутой строки, либо предварительно заполните "a" для всех нулей.

Однако я бы сделал это по-другому, всего с одним циклом:
int *inp = s1;
int *outp = &(a[99]);
do
   {
   copy from inp to outp
   if (inp was a null or you run out of space) exit the loop
   inc inp, dec outp
   } while (true);
Затем напечатать на обратной строкой непосредственно из выходного

Имейте в виду, что эта функция бесполезна, если вы не вернете перевернутую строку - но вы не можете вернуть a или любой указатель на ее часть - она находится в стеке и вызовет серьезные проблемы, если вы это сделаете. Вам нужно будет использовать malloc для выделения пространства, а не объявлять массив в стеке, а затем организовать его освобождение. Было бы лучше передать в функцию как строку, так и область вывода.