Компьютерный форум
Правила
Вернуться   Компьютерный форум > Форум программистов > Языки программирования > Вопросы начинающих программистов
Перезагрузить страницу Проблема с указателями(((( Хелп ми плиз!
Ответ
 
Опции темы Опции просмотра
  (#1 (permalink)) Старый
5neverthesame94 5neverthesame94 вне форума
Member
 
Сообщений: 18
Сказал(а) спасибо: 0
Поблагодарили 0 раз(а) в 0 сообщениях
Регистрация: 19.02.2012
По умолчанию Проблема с указателями(((( Хелп ми плиз! - 19.11.2012, 22:58

Привет)) В общем указатели - моя больная тема. И вот написала я программу,которая переставляет наоборот все слова в строке. Вначале делаю просто реверс строки посимвольно,а потом - реверс каждого слова (тоже посимвольно). Алгоритм рабочий,но с реализацией проблема. Ошибку в коде я пометила... Посмотрите,подскажите,пожалуста,что не так.

Ошибка : Необработанное исключение в "0x013014bc" в "laba4_1.exe": 0xC0000005: Нарушение прав доступа при чтении "0xffffffff".

Прога желательно без функций string.h, но одну я таки себе позволила...strchr,хотя,не уверена,что она уместна..Заранее спасибо...)


#include<stdio.h>
#include<conio.h>
#include<string.h>
#include<stdarg.h>
#define N 10
#define M 31

void reverse(char *str)
{
char *end,*temp_end; //указатель для конца и для сохранения позиции
char temp;
char *str_s=str; //указатель для сохранения позиции начала строки

for(end=str;*end!='\0';end++)
;

end--;

while(str<end){ //общий реверс
temp=*str;
*str=*end;
*end=temp;
str++;end--;
}

str=end=str_s; //сохраняем позиции в начале

while(*end!='\0')
{
end=strchr(str,' '); //находим первый пробел

temp_end=end; //сохраняем
end--;

while(str<end){ //реверс слова
temp=*str;
*str=*end; // ТУТ ОШИБКА!
*end=temp;
str++;end--;
}
str=end=++temp_end; //идём на следующее слово
}
}
void func(char* st1,...)
{
char* pr;
va_list parg; // указатель на неоглашенные параметры

reverse(st1);
puts(st1);

va_start(parg,st1);//устанавливаем указатель на первый неоглаш. параметр

do{
pr=va_arg(parg,char*);
reverse(pr);
puts("\n");
puts(pr);
}while(1);
va_end(parg);
}

int main(void)
{
int i=0;
char string[N][M];

puts("\nEnter strings:\n");

do{
printf("%d)",i+1);
}while(*(gets(string[i++])));

func(string[0],string[1],string[2],string[3]);

getch();
return 0;
}
Ответить с цитированием
  (#2 (permalink)) Старый
Matematic Matematic вне форума
Member
 
Аватар для Matematic
 
Сообщений: 388
Сказал(а) спасибо: 31
Поблагодарили 8 раз(а) в 8 сообщениях
Регистрация: 15.01.2007
По умолчанию 20.11.2012, 00:45

В работе программы не разбирался, она довольно большая.
Но вот первая довольно серьезная ошибка.

do{
pr=va_arg(parg,char*);
reverse(pr);
puts("\n");
puts(pr);
}while(1);

Это вечный цикл, и выхода из него не предусмотрено. Т.е. va_arg должен считать неограниченое число переданных функции параметров из стека, независимо от того, сколько их действительно передано. Это приведет на какой-то итерации цикла к выходу за границы стека и ошибке памяти.

Вообще функция с переменным числом параметров в Си не знает, сколько ей параметров передано и какой тип и какой размер они имеют. Она неспособна это определить ни средствами языка во время компиляции, ни уже во время выполнения. Никаких макросов или иных языковых конструкций для этого в Си не предусмотрено, и это на самом деле недостаток языка. Так что определять все это: количество и типы необязательных параметров, нужно искусственно в самом алгоритме, никаких автоматических средств для этого нет. И вся информация об этих параметрах должна быть известна функции в явном виде.

Хороший пример - функция printf().
Там количество и типы дополнителнительных параметров задаются в первой обязательной строке.
Например, так
char *S; int n; char c;
printf("Result: S = %s, n = %d, c = %c", s, n, c);

Функция printf() разбирает первую строку, находит в ней % и спецификаторы при нем, и в зависимости от этих значков считывает дополнительные параметры. Спецификаторы при проценте определяют типы параметров.

В том виде, в каком она у Вас написана, в функции func() невозможно определить число переданных ей параметров.
Соответственно, функцию func() я бы переписал так:

c Код:
void func(int n,...)
 {
 int i;
 char* pr;
 va_list parg; // указатель на неоглашенные параметры

 va_start(parg, n);//устанавливаем указатель на первый неоглаш. параметр

 for (i=0; i<n; i++) {
 pr=va_arg(parg,char*);
 reverse(pr);
 puts("\n");
 puts(pr);
 }
 va_end(parg);
 }

А ее вызов из main() выглядел бы так:
c Код:
func(4,string[0],string[1],string[2],string[3]);

Последний раз редактировалось Matematic; 20.11.2012 в 01:12
Ответить с цитированием
  (#3 (permalink)) Старый
Matematic Matematic вне форума
Member
 
Аватар для Matematic
 
Сообщений: 388
Сказал(а) спасибо: 31
Поблагодарили 8 раз(а) в 8 сообщениях
Регистрация: 15.01.2007
По умолчанию 20.11.2012, 03:10

Вторая ошибка.
c Код:
while(*end!='\0')
 {
 end=strchr(str,' '); //находим первый пробел

 temp_end=end; //сохраняем
 end--;

 while(str<end){ //реверс слова
 temp=*str;
 *str=*end; // ТУТ ОШИБКА!
 *end=temp;
 str++;end--;
 }
 str=end=++temp_end; //идём на следующее слово
 }

Обратите внимание на определение функции strchr():
char *strchr (char *cs, char c) возвращает указатель на первое вхождение c в cs или, если такового не оказалось, NULL.
Т. е., если пробела в строке cs не оказалось, а так оно и случится при реверсе последнего слова в строке, то strchr() вернет ноль (нулевой указатель).
Что произойдет при анализе последнего слова в строке:
end=strchr(str,' '); //end==0
temp_end=end; //сохраняем - temp_end==0
end--; //end==0xFFFFFFFF (такое значение примет указатель end в шестнадцатиричном коде в случае 32-разрядного процессора). Оно не имеет смысла.


В цикле
while(str<end){ //реверс слова
произойдет ошибка памяти.


Вот Ваша программа с моими заплатками

c Код:
#include<stdio.h>
#include<conio.h>
 #include<string.h>
 #include<stdarg.h>
 #define N 10
 #define M 31

 void reverse(char *str)
 {
 char *end,*temp_end; //указатель для конца и для сохранения позиции
 char temp;
 char *str_s=str; //указатель для сохранения позиции начала строки
 char *end_s; //Указатель для сохранения позиции конца строки. Потребуется при реверсе самого последнего слова, когда все пробелы уже исчерпаны.
 for(end=str;*end!='\0';end++) ;

 end_s=end;
 end--;

 while(str<end){ //общий реверс
 temp=*str;
 *str=*end;
 *end=temp;
 str++;end--;
 }

 str=str_s; //сохраняем позиции в начале

 while(1)
 {
 if(!(end=strchr(str,' '))) end=end_s; //находим первый пробел или конец строки, если все пробелы исчерпаны

 temp_end=end; //сохраняем
 end--;

 while(str<end){ //реверс слова
 temp=*str;
 *str=*end; // ТУТ ОШИБКА!
 *end=temp;
 str++;end--;
 }
 if(!*temp_end) break;
 str=++temp_end; //идём на следующее слово
 }
 }


 void func(int n,...)
 {
 int i;
 char* pr;
 va_list parg; // указатель на неоглашенные параметры

 va_start(parg, n);//устанавливаем указатель на первый неоглаш. параметр

 puts("");

 for (i=0; i<n; i++) {
 pr=va_arg(parg,char*);
 reverse(pr);
 puts(pr);
 }
 va_end(parg);
 }


 int main(void)
 {
 int i=0;
 char string[N][M];

 puts("\nEnter strings:\n");

 do{
 printf("%d)",i+1);
 }while(*(gets(string[i++])));

 func(4,string[0],string[1],string[2],string[3]);

 getch();
 return 0;
 }
Проверьте, у меня вроде заработала.

Последний раз редактировалось Matematic; 20.11.2012 в 03:34
Ответить с цитированием
  (#4 (permalink)) Старый
5neverthesame94 5neverthesame94 вне форума
Member
 
Сообщений: 18
Сказал(а) спасибо: 0
Поблагодарили 0 раз(а) в 0 сообщениях
Регистрация: 19.02.2012
По умолчанию 20.11.2012, 09:56

Большое спасибо,работает) И объяснили доходчиво) В общем,ещё раз огромное спасибо..))
Ответить с цитированием
Ads
Ответ

Опции темы
Опции просмотра

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Trackbacks are Вкл.
Pingbacks are Вкл.
Refbacks are Выкл.


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Проблема с интернетом! Помогите плиз!! witalidze Сетевые подключения 3 17.09.2012 05:26
Проблемс с видюхой видимо ?! плиз хелп Maxnero Видеокарты 18 14.05.2012 08:19
ПЛИЗ ХЕЛП Данияр Накопители 8 22.12.2011 16:36
хелп!!! проблема при переустановке винды laimer Любые вопросы от новичков 1 05.11.2011 18:57
Хелп плиз) swegenk Pascal 3 07.10.2011 11:16
Помогите хелп хелп хелп Помогите плиз Ноутбуки 5 23.08.2011 13:59
комп зависает....ХЕЛП плиз!!!! kuper31rus Любые вопросы от новичков 4 07.07.2011 14:31
проблема с HDD хелп a13xxx Накопители 16 29.03.2011 16:11
Хелп! Проблема с MicroStar MB_Killer Материнские платы 4 24.12.2010 11:26
Как работать с указателями в С++ rusl Вопросы начинающих программистов 34 03.06.2009 18:17
плиз, хелп! tokito Офтопик 2 27.05.2005 17:13



Powered by vBulletin® Version 3.8.7
Copyright ©2000 - 2018, Jelsoft Enterprises Ltd.
Нardforum.ru - компьютерный форум и программирование, форум программистов