• Добро пожаловать на компьютерный форум Tehnari.ru. Здесь разбираемся с проблемами ПК и ноутбуков: Windows, драйверы, «железо», сборка и апгрейд, софт и безопасность. Форум работает много лет, сейчас он переехал на новый движок, но старые темы и аккаунты мы постарались сохранить максимально аккуратно.

    Форум не связан с магазинами и сервисами – мы ничего не продаём и не даём «рекламу под видом совета». Отвечают обычные участники и модераторы, которые следят за порядком и качеством подсказок.

    Если вы у нас впервые, загляните на страницу о форуме и правила – там коротко описано, как задать вопрос так, чтобы быстро получить ответ. Чтобы создавать темы и писать сообщения, сначала зарегистрируйтесь, а затем войдите под своим логином.

    Не знаете, с чего начать? Создайте тему с описанием проблемы – подскажем и при необходимости перенесём её в подходящий раздел.
    Задать вопрос Новые сообщения Как правильно спросить
    Если пришли по старой ссылке со старого Tehnari.ru – вы на нужном месте, просто продолжайте обсуждение.

Паскаль. Обработка массива.

Montespan

Новые
Регистрация
1 Ноя 2009
Сообщения
13
Реакции
0
Баллы
0
Паскаль. Обработка массива.

Изменить таблицу, заменив каждый ее элемент на сумму исходных элементов, лежащих не выше и не правее его, а также не ниже и не левее.

Подскажите, пожалуйста,
1) имеет ли смысл в данной задаче использовать рекурсию?
2) начать обработку таблицы лучше всего с конца? или с начала?
ведь результат получится разным.
 
При решении нельзя создавать таблицу таких же размеров, массив должен быть динамическим.
Примерное решение: cc9c4254ae0b.webp
подсчитать сумму элементов в массиве, а значения элементов новой таблицы посчитать как (сумма элементов исходной матрицы - значение самого элемента - сумма элементов, лежащих "выше и правее" - сумма элементов, лежащих "ниже и левее" ). Создать 2 одномерных массива, первый- для подсчета суммы элементов по столбцам, второй- для подсчета суммы элементов по строкам.
При реализации этого алгоритма возникают проблемы- не понимаю, как правильно написать это на паскале, использую динамику.
 
1)Использовать рекурсию здесь нежелательно. Слишком сложно будет уместить в голове происходящее.
2)На мой взгляд, считать нужно так, чтобы полученные значения не вовлекались в процесс счета.
3)Иногда стоит создать решение типа "лишь бы работало" - без ограничений задачи, а затем, как следует на него насмотревшись, построить решение по всем правилам.
 
Long Cat, спасибо.
Без динамики написать получилось, но возникло несколько вопросов.
1)Если в функции массив входно-выходной параметр, как правильно его описать? в var?
2)Если использовать дополнительно одномерный динамический массив, выделять для него память нужно в самой функции?
И вообще при работе с динамическими массивами освобождать память под них достаточно один раз?
 
Код:
type
TInt=integer;
MyType=real;
Matrix=array[1..1] of MyType;
PMatrix=^Matrix;      {cтроки}
MyArray=array[1..1] of PMatrix;
PMyArray=^MyArray;        {массив указателей на строки}
{-------------------------------------------------}
Function Summa( a:PMyArray; c,d,n,m: TInt): MyType;
{вх.параметр a-динамический двумерный массив, c,m-счетчики по столбцам, n,d- по строкам, функция считает сумму элементов, лежащих не выше и не правее и не ниже и не левее данного}
var i,j: TInt;
s: MyType;
begin
s:=0;
for i:=1 to d do
 for j:=1 to c do
  s:=s+a^[i]^[j];
for i:=d to n do
 for j:=c to m do
  s:=s+a^[i]^[j];
summa:=s-2*a^[d]^[c];
end;
{------------------------------}
Function Tabl (a:PMyArray; n,m: TInt): Boolean;
var b: Matrix; {дополнительный массив для хранения новых элементов}
c,d,e,i,j: TInt;
begin
if(m<0) or (n<0) or (a=nil) then
Tabl:=false
else
begin
 for c:=1 to m do
  begin
   for d:=1 to n do
    b[m*(d-1)+c]:=summa(a,c,d,n,m);
    end;
 begin
  for i:=1 to n do
  begin
   for j:=1 to m do
    begin
     for e:=1 to m*n do
    a^[i]^[j]:=b[e];
    end;
   end;
end;
end;
Выдает синтаксическую ошибку во второй функции на этом месте for j:=1 to m do
Подскажите, пожалуйста, что неверно?
 
Последнее редактирование модератором:
Выдает синтаксическую ошибку во второй функции на этом месте for j:=1 to m do
Подскажите, пожалуйста, что неверно?

Я не вникал в Вашу программу, тем более, что с динамическими переменными "плаваю", но у Вас имеется нестыковка в количестве begin - end ("begin" на 1 больше). И вообще, расстановка этих т.н. "операторных скобок" вызывает некоторые недоумения. Какой, например, смысл в том "begin", который идет сразу после строк
b[m*(d-1)+c]:=summa(a,c,d,n,m);
end; ?
 
Без динамики написать получилось, но возникло несколько вопросов.
1)Если в функции массив входно-выходной параметр, как правильно его описать? в var?
2)Если использовать дополнительно одномерный динамический массив, выделять для него память нужно в самой функции?
И вообще при работе с динамическими массивами освобождать память под них достаточно один раз?
Чтобы передавать массив функции в качестве параметра, правильнее всего использовать передавать указатель на массив. В противном случае, программа при каждом вызове функции будет копировать в стек весь массив - либо стека не хватит, либо программа будет работать очень долго.

Про динамические переменные:
Здесь нужно соблюдать строгий порядок работы:
1) Выделяем память.
2) Работаем.
3) Освобождаем память.
Т. е. на каждую операцию new должна в процессе работы должна вызываться соответствующая dispose. (Количество вызовов new и dispose во время работы программы должно совпадать).

При форматировании текста программы удобно придерживаться таких правил:
1) begin и парный ему end должны быть напечатаны с одной горизонтальной позиции - тогда меньше придется искать синтаксических ошибок и проще разбирать код.
2) Даже если тело цикла или условного оператора состоит из одной команды, стоит поставить begin и end - лечит огромное количество ошибок.

И да, чтобы получить быстрый ответ на вопрос "компилятор там-то выдает ошибку", стоит приводить полный и оригинальный текст сообщения об ошибке.
 
Последнее редактирование:
При форматировании текста программы удобно придерживаться таких правил:
1) begin и парный ему end должны быть напечатаны с одной горизонтальной позиции - тогда меньше придется искать синтаксических ошибок и проще разбирать код.
2) Даже если тело цикла или условного оператора состоит из одной команды, стоит поставить begin и end - лечит огромное количество ошибок.


С п.1 соглашаюсь абсолютно - но увы, новички народ упрямый.
А вот п.2 представляется весьма и весьма спорным. Во всяком случае, я этого правила никогда не придерживаюсь. Потому что, с моей точки зрения, например, заполнять матрицу единицами лучше (читабельнее) так:
Код:
for i:=1 to N do
 for j:=1 to M do
  A[i,j]:=1;
чем так:
Код:
for i:=1 to N do
 begin
  for j:=1 to M do
   begin
    A[i,j]:=1;
   end;
 end;
А Montespan как раз и наворотила столько этих операторных скобок, что в них же малость и утонула.
Но это, конечно, дело вкуса и стиля. Ни в коем случае не пытаюсь свою точку зрения кому бы то ни было навязать.
 
Последнее редактирование модератором:
Спасибо, буду иметь ввиду.
Теперь компиллятор ошибок не выдает, но и исправленная функция не работает.
Программа реализована как меню. Первый пункт работает хорошо, когда выбираю второй, ничего не происходит.
PHP:
program tablica;
uses crt;

type
  TInt=integer;
  MyType=real;
  Matrix=array[1..1] of MyType;
  PMatrix=^Matrix;
   {cтроки}
  MyArray=array[1..1] of PMatrix;
  PMyArray=^MyArray;
    {массив указателей на строки}
  TF=file of MyType;
  TStr=string;

const k=50;

var
  n,m,i,j,key,z,q:TInt;
  a:PMyArray;
  IOR:word;
  flag1, flag2: boolean;
  f: TF;
  name: Tstr;

{------------------------------------}
Function GetMemory(m,n: TInt; var a: PMyArray):boolean;
{Функция выделяет память под динамический массив, входные параметры:
 m- столбцы, n- строки, а- двумерный динамический массив}
var  i: TInt;
begin
  { Выделяем память под указатели на "строки" }
  getmem(a,  n*sizeof(PMatrix));
  if(a<>nil) then
    begin
      for i:= 1 to n do
         getmem(a^[i], m*sizeof(MyType));
      GetMemory:=true;
    end
    else
      GetMemory:=false;
end;
{--------------------------------}
Function Summa( a:PMyArray; c,d,n,m: TInt): MyType;
{функция считает для каждого элемента сумму элементов,
 стоящих не выши и не правее, а также не ниже и не левее его,
 c- счетчик по столбцам, d-счетчик по строкам}
var i,j: TInt;
    s: MyType;
begin
  s:=0;
  for i:=1 to d do
    for j:=1 to c do
      s:=s+a^[i]^[j];
  for i:=d to n do
    for j:=c to m do
      s:=s+a^[i]^[j];
  summa:=s-2*a^[d]^[c];
end;
{------------------------------}
Function Tabl (var a:PMyArray; n,m: TInt): Boolean;
{функция присваивает элементам одномерного массива b
 значения функции Summa, затем переприсваивает их массиву а,
  тем самым изменяя его}
var
  b: PMatrix;
  c,d,e,i,j: TInt;
begin
  if(m<0) or (n<0) or (a=nil)
    then
      Tabl:=false
    else
      begin
        Tabl:=true;
	GetMem(b, n*sizeof(MyType));
        for c:=1 to m do
          begin
            for d:=1 to n do
              b^[m*(d-1)+c]:=summa(a,c,d,n,m);
            for i:=1 to n do
              for j:=1 to m do
                for e:=1 to m*n do
                  a^[i]^[j]:=b^[e];
          end;
      for i:=1 to n do
      begin
        for j:=1 to m do
          write(a^[i]^[j]:6:2);
        writeln;
      end;
      readln;
	FreeMem(b, n*sizeof(MyType));
      end;
end;
{---------------------------------------------------------------}
Procedure FreeMemory(var a:PMyArray;n,m:TInt);
var i:TInt;
begin
  for i := 1 to m do
    freemem(a^[i], m*sizeof(MyType));
  freemem(a, n*sizeof(PMatrix));
end;
{--------------------------------}
Procedure Make_Tabl(n,m: TInt; var a: PMyArray);
var
  i,j: TInt;
  f: file of MyType;
  temp: MyType;
begin
  n:=-1;
  m:=-1;
  {$I-}
  repeat
    clrscr;
    writeln ('Введите длину таблицы.  ');
    readln (n);
    IOR:=ioresult;
  until (IOR=0) and (n>=1);
  repeat
    clrscr;
    writeln ('Введите ширину таблицы. ');
    readln (m);
    IOR:=ioresult;
  until (IOR=0) and (m>=1);
  {$I+}

  if(GetMemory(m,n,a)=true)
  then
    begin
      {$I-}
      repeat
        clrscr;
        writeln ('Выберете способ ввода значений таблицы');
        writeln ('1- если хотите выполнить ввод с клавиатуры');
        writeln ('2- для случайного вводa');
        writeln ('3- для чтения из файла');
        readln (z);
        IOR:=ioresult;
      until (IOR=0) AND ((z=1) or (z=2) or (z=3));
      {$I-}
      if z=1
      then
        begin
          for i:=1 to n do
              for j:=1 to m do
                begin
                  {$I-}
                  repeat
                    write('Введите значение ячейки таблицы a[',i,',',j,'] ');
                    readln (a^[i]^[j]);
                    IOR:=ioresult;
                    if IOR<>0 THEN WriteLn('Неверное значение!');
                  until IOR=0;
                  {$I+}
                end;
        end;

      if z=2
      then
        begin
          randomize;
          for i:=1 to n do
            for j:=1 to m do
              a^[i]^[j]:=random(k);
        end;

      if z=3
      then
        begin
          {$I-}
          repeat
            writeln('Введите полное имя файла: ');
            readln(name);
            assign(f,name);
            reset(f);
            IOR:=IOResult;
            if IOR<>0 then writeLn('Неверное имя файла!');
          until IOR=0;
          {$I+}
          read(f,temp); {строки}
          n:=trunc(temp);
          read(f,temp); {cтолбцы}
          m:=trunc(temp);
	        FreeMemory(a,n,m);
          if (GetMemory(m,n,a)=true)
          then
            begin
              for i:=1 to n do
                for j:=1 to m do
                  begin
                  {$I-}
                    read(f, a^[i]^[j]);
                    IOR:=IOResult;
                  {$I+}  
                    if IOR<>0
                    then
                      begin
                        writeLn('Неверное содержание файла. Нажмите Enter для выхода.');
                        readLn;
                        close(f);
                        halt; {завершение работы программы, код завершения 0}
                      end;
                  end;    
                  close(f);
            end
          else
            writeln('Произошла ошибка.');
        end
      else
        writeln('Error!');
    end;
end;
{-------------------------------------------}
begin
  repeat
  clrscr;
  writeln('Меню');
  writeln('1.Создание таблицы.');
  writeln('2.Обработка таблицы и вывод результата.');
  writeln('3.Сохранение файла.');
  writeln('4.Выход из программы.');
  readln(key);
  case key of
  1:
  begin
    Make_Tabl(n,m,a);
    flag1:=true;
  end;
  2:
  if flag1 then
    begin
      Tabl(a,m,n);
    end;
    end;
  until key=4;
end.
 
Переменная flag1 перед запуском цикла опроса клавиатуры должна быть инициализирована.
 
Спасибо, буду иметь ввиду.
Теперь компиллятор ошибок не выдает, но и исправленная функция не работает.
Программа реализована как меню. Первый пункт работает хорошо, когда выбираю второй, ничего не происходит.

Попробуйте сделать две вещи:
1. Убрать из заголовка функции Tabl слово "var" - оно там явно не к месту.
2. Вызов функции Tabl в теле программы осуществить, как bbbb:=Tabl(a,m,n); , где bbbb - некая булева переменная. Хотя вроде бы Паскаль допускает такой, как у Вас, "голый" вызов функций, но кто знает...
 
Назад
Сверху