Archiv značek: matrice. Technologie programování C: reprezentace matic, práce se soubory a texty Výstup všech prvků obdélníkové matice C

Obecně není potřeba programovat výpočet determinantů. Lze je spočítat řekněme vestavěnou funkcí MOPRED z Excelu:

  • shromažďujeme prvky matice v sousedních buňkách, například matice 4 * 4 je zobrazena na obrázku;
  • do požadované buňky zadejte vzorec (v našem případě =MOPRED(A1:D4) a stiskněte Enter:)

Počítání v MathCADu není o nic složitější – stačí kliknout na tlačítko na maticovém panelu...

Ale někdy potřebujete algoritmus, ne odpověď... zde je nějaký kód v konzoli C++, nepředstírá, že je dokonalý, ale nuly v matici nebo „špatné“ pořadí prvků by nemělo zmást determinantní funkci. Příklad z main - 1001. pro práci s dynamickou maticí pomocí C++ :) Zbytek je okomentován ve zdrojovém kódu.

#define bool int #define true 1 #define false 0 int search (double **a, int m, int n, double what, bool match, unsigned int &uI, unsigned int &uJ, unsigned int starti, unsigned int startj) ( / / Hledat v matici a[m][n] prvek se zadanou hodnotou what // Jeho číslo řádku a sloupce uI, uJ je vráceno, pokud je prvek nalezen // shoda - hledání prvku rovného nebo odlišného od zadaného // Vrátí 0 - nenalezeno, ne 0 - nalezeno if ((!m) || (!n)) vrátí 0, pokud ((starti >= n) || (startj >= m)) návrat 0; pro (bez znaménka int i = starti; i< n; i++) for (unsigned int j = startj; j < m; j++) { if (match == true) { if (a[i][i] == what) { uI = i; uJ = j; return 1; } } else if (a[i][j] != what) { uI = i; uJ = j; return 1; } } return 0; } void swaprows (double **a, int n, int m, unsigned int x1, unsigned int x2) { //Меняет в матрице a[n][m] строки с номерами x1 и x2 местами if ((!n) || (!m)) return; if ((x1 >= n) || (x2 >= n) || (x1 == x2)) return; dvojitá tmp; for (bez znaménka int x = 0; x< m; x++) { tmp = a[x]; a[x] = a[x]; a[x] = tmp; } return; }; void swapcolumns (double **a, int n, int m, unsigned int x1, unsigned int x2) { //Меняет в матрице a[n][m] столбцы с номерами x1 и x2 местами if ((!n) || (!m)) return; if ((x1 >= m) || (x2 >= m) || (x1 == x2)) return; dvojitá tmp; for (bez znaménka int x = 0; x< n; x++) { tmp = a[x]; a[x] = a[x]; a[x] = tmp; } return; }; double determinant (double **a, unsigned int n) { //Вычисление определителя квадратной матрицы a[n][n] unsigned int m = n; if (m == 0) return 0; if (m == 1) return a; if (m == 2) return (a * a - a * a); bool sign = false; // смена знака определителя. по умолчанию - нет double det = 1; // определитель double tmp; unsigned int x, y; for (unsigned int i = 0; i < n; i++) { // цикл по всей главной диагонали if (a[i][i] == 0) { // если элемент на диагонали равен 0, то ищем ненулевой элемент в матрице if (!search(a,m,n,0, false, y, x, i, i)) return 0; // если все элементы нулевые, то опр. = 0 if (i != y) { // меняем i-ую строку с y-ой swaprows(a,m,n,i, y); sign = !sign; } if (i != x) { // меняем i-ый столбец с x-ым swapcolumns(a,m,n,i, x); sign = !sign; } // таким образом, в a[i][i], теперь ненулевой элемент. } // выносим элемент a[i][i] за определитель det *= a[i][i]; tmp = a[i][i]; for (x = i; x < m; x++) { a[i][x] = a[i][x] / tmp; } // таким образом a[i][i] теперь равен 1 // зануляем все элементы стоящие под (i, i)-ым, // при помощи вычитания с опр. коеффициентом for (y = i + 1; y < n; y++) { tmp = a[y][i]; for (x = i; x < m; x++) a[y][x] -= (a[i][x]*tmp); } } if (sign) return det*(-1); return det; }; #include int main () ( const int n=4; int data = ( 5,4,3,2, 11,-1,2,7, 0,1,0,4, -13,79,1,2 ); int i,j,k=0; double **a = new double * [n];

Anotace: Jsou uvedeny správné a nesprávné způsoby implementace matic a vícerozměrných polí v jazyce C. Práce s maticemi je ilustrována na příkladu redukce matice do stupňovitého tvaru pomocí Gaussovy metody. Popisuje metody pro práci se soubory pomocí I/O funkcí ze standardní knihovny ANSI. Poskytuje způsoby práce se znaky a textovými řetězci pomocí standardních funkcí knihovny. Materiál je ilustrován příklady, včetně programu "wc" pro počítání znaků, slov a řádků v souboru a programu "Address Book", který umožňuje vyhledat telefonní číslo osoby podle jejího jména a také uložit a upravit obsah knihy.

Reprezentace matic a vícerozměrných polí

Speciální datový typ matrice popř vícerozměrné pole v C neexistuje, můžete však použít pole prvků typu pole. Například proměnná a představuje matici 3x3 se skutečnými prvky:

Prvky matice jsou umístěny v paměti postupně v řádcích: nejprve jsou řádkové prvky s indexem 0, poté řádky s indexem 1 a na konci řádku s indexem 2 (v programování začíná počítání indexů vždy od nuly, nikoli od jednoho!). V tomto případě výraz

kde i je celočíselná proměnná, je ukazatelem na počáteční prvek i-tého řádku a je typu double*.

Chcete-li získat přístup k prvku matice, musíte napsat jeho indexy do hranatých závorek, například výraz

představuje prvek matice a na řádku indexu i a sloupci na indexu j. Prvek matice lze použít v libovolném výrazu jako regulární proměnnou (můžete například přečíst jeho hodnotu nebo přiřadit novou).

Tato implementace matice je pohodlná a nejefektivnější z hlediska doby přístupu k prvkům. Má to pouze jednu významnou nevýhodu: takto můžete implementovat pouze matici, jejíž velikost je předem známa. Jazyk C neumožňuje popisovat pole proměnné velikosti, velikost pole musí být známa před spuštěním programu, ve fázi kompilace.

Předpokládejme, že potřebujeme matici, jejíž velikost se určuje za běhu programu. Pak je třeba prostor pro něj zachytit do dynamické paměti pomocí funkce malloc jazyka C nebo operátoru new jazyka C++. V tomto případě je lineární pole zachyceno v dynamické paměti a je vrácen ukazatel na něj. Uvažujme skutečnou matici m řádků krát n sloupců. Získávání paměti se provádí pomocí funkce C malloc

dvojité *a; . . . a = (double *) malloc(m * n * sizeof(double));

nebo pomocí nového operátoru C++:

dvojité *a; int m, n; . . . a = nový dvojitý;

V tomto případě se předpokládá, že prvky matice budou umístěny v poli takto: nejprve jsou prvky řádku s indexem 0, potom prvky řádku s indexem 1 atd. a jako poslední jsou prvky řádku s indexem m - 1. Každý řádek se skládá z n prvků, proto index prvků řádku i a sloupce j v lineárním poli je

(ve skutečnosti, protože indexy začínají od nuly, i se rovná počtu řádků, které je třeba přeskočit, i * n je celkový počet prvků ve vynechaných řádcích; číslo j se rovná posunu uvnitř posledního řádku) . Prvek matice v řádku i a sloupci j tedy odpovídá výrazu

Tento způsob reprezentace matice je pohodlný a účinný. Jeho hlavní výhodou je, že maticové prvky jsou uloženy v kontinuální paměťový segment. Za prvé, umožňuje optimalizačnímu kompilátoru transformovat text programu a dosáhnout tak maximálního výkonu; za druhé, při spouštění programu je maximálně využit mechanismus vyrovnávací paměti, což minimalizuje přístupy do paměti a výrazně zrychluje program.

Některé knihy C doporučují implementovat matici jako pole ukazatelů na její řádky, přičemž paměť pro každý řádek je zachycena samostatně v dynamické paměti:

dvojité **a; // Adresa pole ukazatelů int m, n; // Rozměry matice: m řádků, n sloupců int i; . . . // Zachytí paměť pro pole ukazatelů a = (double **) malloc(m * sizeof(double *)); pro (i = 0; i< m; ++i) { // Захватывается память под строку с индексом i a[i] = (double *) malloc(n * sizeof(double)); }

K prvku a ij lze pak přistupovat pomocí výrazu

I přes složitost tohoto řešení nedochází k žádnému zisku, naopak program ztrácí na rychlosti! Důvodem je, že matice není uložena v souvislé oblasti paměti, což narušuje optimalizaci programu i efektivní využití mezipaměti. Je tedy lepší tuto metodu maticové reprezentace nepoužívat.

Vícerozměrná pole jsou implementována podobně jako matice. Například skutečné trojrozměrné pole o velikosti 4 x 4 x 2 je popsáno jako

přístup k jeho prvku s indexy x, y, z se provádí pomocí výrazu

Vícerozměrná pole proměnlivé velikosti s počtem indexů větším než dva se v programech vyskytují poměrně zřídka, ale s jejich implementací nejsou žádné problémy: implementují se podobně jako matice. Řekněme například, že potřebujeme implementovat trojrozměrné reálné pole o velikosti m x n x k . Je zachyceno lineární pole reálných čísel velikosti m * n * k:

dvojité *a; . . . a = (double *) malloc(m * n * k * sizeof(double));

K prvku s indexy x, y, z se přistupuje pomocí výrazu

a[(x * n + y) * k + z]

Příklad: redukce matice na stupňovitý tvar pomocí Gaussovy metody

Jako příklad práce s maticemi uvažujme Gaussův algoritmus pro redukci matice do stupňovitého tvaru. Gaussova metoda je jedním z hlavních výsledků lineární algebry a je na ni redukováno mnoho dalších teorémů a metod lineární algebry (teorie a výpočet determinantů, řešení soustav lineárních rovnic, výpočet hodnosti matice a další; inverzní matice, teorie bází konečnorozměrných vektorových prostorů atd. .).

Připomeňme, že matice A s prvky a ij se nazývá postupná, pokud má následující dvě vlastnosti:

  1. pokud je v matici nulový řádek, pak všechny řádky pod ní jsou také nulové;
  2. nechť a ij nerovná se 0 je první nenulový prvek v řadě s indexem i, tzn. prvky a il = 0 pro l< j . Тогда все элементы в j -м столбце ниже элемента a ij равны нулю, и все элементы левее и ниже a ij также равны нулю: a kl = 0 при k >i a l =< j .

Kroková matice vypadá asi takto:

zde jsou první nenulové prvky řádků matice označeny tmavými čtverečky. Nulové prvky jsou zobrazeny bíle, libovolné prvky jsou zobrazeny šedě.

Gaussův algoritmus používá dva typy transformací elementární matice.

  • Transformace prvního druhu: dva řádky matice jsou prohozeny a znaménka všech prvků jednoho z řádků jsou obrácená.
  • Transformace druhého druhu: k jednomu řádku matice se přidá další řádek, vynásobený libovolným číslem.

Elementární transformace zachovávají determinant a hodnost matice, stejně jako množinu řešení lineárního systému. Gaussův algoritmus elementárními transformacemi redukuje libovolnou matici na stupňovitý tvar. U stupňovité čtvercové matice je determinant roven součinu diagonálních prvků a hodnost je počet nenulových řádků (podle definice je hodnost rozměr lineární plášť strun matrice).

Gaussova metoda ve své matematické verzi je následující:

  1. hledat jako první nenulové prvek v prvním sloupci. Pokud jsou všechny prvky prvního sloupce nulové, přejděte do druhého sloupce a tak dále. Najdeme-li v k-té řadě nenulový prvek, pak pomocí elementární transformace prvního druhu prohodíme první a k-tý řádek a zajistíme, že první prvek prvního řádku bude jiný než nula;
  2. Pomocí elementárních transformací druhého druhu resetujeme všechny prvky prvního sloupce, počínaje druhým prvkem. Chcete-li to provést, odečtěte první řádek od čísla řádku k, vynásobený koeficientem a k1 /a 11 .
  3. přejděte do druhého sloupce (nebo j-tého, pokud by všechny prvky prvního sloupce byly nulové) a v budoucnu budeme uvažovat pouze část matice, počínaje druhým řádkem a níže. Body 1) a 2) opakujeme znovu, dokud matici nezredukujeme do stupňovité formy.

Programátorská verze Gaussovy metody má tři rozdíly od matematické:

r = -a kj /a ij . a k = a k + r * a i

Toto schéma funguje normálně pouze tehdy, když koeficient r v absolutní hodnotě nepřekročí jednotku. V opačném případě se zaokrouhlovací chyby násobí velkým faktorem a rostou tedy exponenciálně. Matematici tento jev nazývají nestabilita výpočetní obvod. Pokud je výpočetní schéma nestabilní, pak výsledky získané s jeho pomocí nemají žádný vztah k původnímu problému. V našem případě je schéma stabilní, když koeficient r = -a kj /a ij nepřekročí v absolutní hodnotě jednotku. K tomu musí být splněna nerovnost

|a ij | >= |a kj | pro k > i

Z toho vyplývá, že při hledání rozlišovacího prvku v j-tém sloupci je nutné najít nikoli první nalezený nenulový prvek, ale maximum v absolutní hodnotě. Pokud jeho modul nepřesáhne , pak předpokládáme, že všechny prvky sloupce jsou nulové; v opačném případě prohodíme řádky, umístíme je na vrchol sloupce a poté sloupec vynulujeme elementárními transformacemi druhého druhu.

Níže je uveden úplný text programu C, který redukuje skutečnou matici na stupňovitou formu. Funkce, která implementuje Gaussovu metodu, současně vypočítá hodnost matice. Program zadá z klávesnice rozměry matice a jejích prvků a zavolá funkci zmenšení do stupňovitého tvaru. Program poté vytiskne echelon matice a její pořadí. V případě čtvercové matice se také počítá a tiskne maticový determinant, rovný součinu diagonálních prvků krokové matice.

Při implementaci Gaussovy metody je použito schéma konstrukce cyklu s použitím invariantu, viz část 1.5.2. V cyklu se mění dvě proměnné - řádkový index i, 0 =< i < m - 1 , и индекс столбца j , 0 =< j < n - 1 . Инвариантом цикла является утверждение о том, что часть матрицы (математики говорят Méně důležitý) ve sloupcích 0,1,...j - 1 je redukován na stupňovitý tvar a že první nenulový prvek v řádku i - 1 je ve sloupci s indexem menším než j . V těle smyčky je v řádcích i,...,m - 1 a sloupcích j,...,n - 1 uvažována pouze malá část matice. Nejprve se hledá prvek s maximální absolutní hodnotou v j-tém sloupci. Pokud nepřekročí v absolutní hodnotě, pak se j zvýší o jedna (sloupec se považuje za nulový). V opačném případě se přeuspořádáním řádků umístí rozlišovací prvek na vrchol j-tého sloupce vedlejšího prvku a poté se sloupec vynuluje pomocí elementárních transformací druhého druhu. Poté se oba indexy i a j zvýší o jednu. Algoritmus končí, když je i = m nebo j = n. Na konci algoritmu je hodnota proměnné i rovna počtu nenulových řádků krokové matice, tzn. hodnost původní matice.

Pro výpočet absolutní hodnoty reálného čísla x typu double použijeme standardní matematickou funkci fabi(x), popsaný ve standardním záhlaví souboru " math .h.

#zahrnout // Popis I/O funkcí #include // Popisy matematických funkcí #include // Popisy malloc a volných funkcí // Prototyp funkce pro redukci matice // do echelonového tvaru. // Funkce vrací hodnost matice int gaussMethod(int m, // Počet řádků matice int n, // Počet sloupců matice double *a, // Adresa pole prvků matice double eps // Přesnost výpočtu); int main() ( int m, n, i, j, pořadí; double *a; double eps, det; printf("Zadejte rozměry matice m, n: "); scanf("%d%d", &m, &n ); // Zachycení paměti pro prvky matice a = (double *) malloc(m * n * sizeof(double)("Zadejte prvky matice:\n");< m; ++i) { for (j = 0; j < n; ++j) { // Вводим элемент с индексами i, j scanf("%lf", &(a)); } } printf("Введите точность вычислений eps: "); scanf("%lf", &eps); // Вызываем метод Гаусса rank = gaussMethod(m, n, a, eps); // Печатаем ступенчатую матрицу printf("Ступенчатый вид матрицы:\n"); for (i = 0; i < m; ++i) { // Печатаем i-ю строку матрицы for (j = 0; j < n; ++j) { printf(// Формат %10.3lf означает 10 "%10.3lf ", // позиций на печать числа, a // 3 знака после точки); } printf("\n"); // Перевести строку } // Печатаем ранг матрицы printf("Ранг матрицы = %d\n", rank); if (m == n) { // Для квадратной матрицы вычисляем и печатаем // ее определитель det = 1.0; for (i = 0; i < m; ++i) { det *= a; } printf("Определитель матрицы = %.3lf\n", det); } free(a); // Освобождаем память return 0; // Успешное завершение программы } // Приведение вещественной матрицы // к ступенчатому виду методом Гаусса с выбором // максимального разрешающего элемента в столбце. // Функция возвращает ранг матрицы int gaussMethod(int m, // Число строк матрицы int n, // Число столбцов матрицы double *a, // Адрес массива элементов матрицы double eps // Точность вычислений) { int i, j, k, l; double r; i = 0; j = 0; while (i < m && j < n) { // Инвариант: минор матрицы в столбцах 0..j-1 // уже приведен к ступенчатому виду, и строка // с индексом i-1 содержит ненулевой эл-т // в столбце с номером, меньшим чем j // Ищем максимальный элемент в j-м столбце, // начиная с i-й строки r = 0.0; for (k = i; k < m; ++k) { if (fabs(a) >r) ( l = k; // Zapamatujte si číslo řádku r = fabs(a); // a max. prvek ) ) jestliže (r<= eps) { // Все элементы j-го столбца по абсолютной // величине не превосходят eps. // Обнулим столбец, начиная с i-й строки for (k = i; k < m; ++k) { a = 0.0; } ++j; // Увеличим индекс столбца continue; // Переходим к следующей итерации } if (l != i) { // Меняем местами i-ю и l-ю строки for (k = j; k < n; ++k) { r = a; a = a; a = (-r); // Меняем знак строки } } // Утверждение: fabs(a) >eps // Resetujte j-tý sloupec, počínaje řádkem i+1, // pomocí prvku. transformace druhého druhu pro (k = i+1; k< m; ++k) { r = (-a / a); // К k-й строке прибавляем i-ю, умноженную на r a = 0.0; for (l = j+1; l < n; ++l) { a += r * a; } } ++i; ++j; // Переходим к следующему минору } return i; // Возвращаем число ненулевых строк }

Matice lze samozřejmě ze vstupních dat rekonstruovat, triviálně je vynásobit a výsledek zobrazit v daném tvaru. Jako příklad špatného stylu programování: naivní algoritmus vede k téměř dvojnásobnému množství spotřebované paměti a má výrazně nižší výkon. Existuje další řešení, kterého lze dosáhnout postupným přizpůsobením standardních maticových operací formátu vstupních dat.

Největší obtíž, jak výpočetní, tak koncepční, je násobení matic, v tomto případě kvadratura. Následující sekvence kroků vám umožní násobit symetrické matice pomocí jejich lineární reprezentace ve formátu zdrojových dat.

Poznámka 1

Podprostor symetrických matic není při násobení uzavřen: součin dvou symetrických matic může být asymetrická matice.

Příklad

\left(\begin(pole)(ccc) 1 & 1 & 3 \\ 1 & 4 & 5 \\ 3 & 5 & 0\end(pole) \right) \cdot \left(\begin(pole)(ccc ) 4 & 0 & 0 \\ 0 & 4 & 3 \\ 0 & 3 & 2 \end(pole) \right) = \left(\begin(pole)(ccc) 4 & 13 & 9 \\ 4 & 31 & 22 \\ 12 & 20 & 15 \konec (pole) \vpravo)

Poznámka 2

Stupeň symetrické matice je také symetrická matice. Důkaz je založen na zobrazení matice jako zobrazení lineárního operátoru a na vlastnostech hermitovských operátorů.

Ve všech dalších výpočtech se předpokládá, že matice je reprezentována lineárním polem prvků \frac(n(n+1))(2).

Nejprve si všimneme, že prvek c_(i,j) matice C=A^(2) je roven skalárnímu součinu (jako vektory ve standardní bázi) i-tého řádku matice A o jeho j-tý řádek (vzhledem k tomu, že v symetrické matici se j-tý řádek shoduje s j-tým sloupcem). Pro povýšení symetrické matice na mocninu je tedy nutné a postačující implementovat operaci skalárního násobení jejích dvou řad.

Pak musíte pochopit, jak získat jeho i-tý řádek z dané maticové reprezentace. Pro usnadnění zapisujeme dostupné prvky ve formě kompletní matice. Všimněte si, že první prvek i-tého řádku bude i-tým prvkem prvního řádku a zobecněte toto pozorování. Označme pozici pro nás aktuálního prvku v i-té řadě jako j. Pokud j< i, то следует выбрать i-ый элемент j-ой строки, иначе следует выбрать все элементы j-ой строки, лежащие правее данного. Графически можно интерпретировать алгоритм таким образом: начиная с i-го элемента первой строки, спускаться вертикально вниз по матрице до тех пор, пока не будет достигнута i-ая строка, далее — двигаться вправо до конца строки. Наглядность алгоритма позволяет легко воплотить его программно.
Stačí sledovat, jak se při pohybu po řádcích matice mění vzdálenosti mezi prvky ležícími pod sebou, což usnadní přenos algoritmu do lineární reprezentace horní trojúhelníkové matice. Vyzýváme čtenáře, aby provedl toto jednoduché, ale vizuální cvičení pro lepší pochopení algoritmu.

Nyní můžete přejít přímo k implementaci.

. Pro koho je modul určen?

Tento modul je určen pro studenty středních a vysokých škol. Musíte zvládnout taková témata, jako je práce se smyčkami, s ukazateli, musíte vědět, co je to jednorozměrné pole.

II. Motivace

Už víme, proč bychom mohli potřebovat jednorozměrná pole. Můžeme například uložit koeficienty kvadratické rovnice do jednorozměrného pole a vypočítat kořeny pomocí diskriminantu. Co když potřebujeme vypočítat mnoho takových rovnic? Je opravdu možné pokaždé přepsat nové koeficienty místo starých? Co když je potřeba se vrátit k těm již vypočítaným? Nebo potřebujeme vyřešit soustavu více rovnic, tzn. Potřebujete pracovat se všemi současně? Pokud si jen potřebujeme uložit tabulku nějakých hodnot, například měření během experimentu, jak to můžeme udělat s využitím znalostí, které jsme již získali?

Pro každý z výše uvedených případů můžete jednoduše deklarovat několik jednorozměrných polí, ale bude příjemné pracovat s tolika? Ostatně každý bude potřeba pojmenovat a zpracovat zvlášť. Situace je podobná, jako když jsme právě představili koncept jednorozměrného pole. Zde přichází na pomoc dvourozměrná pole.

III. Prezentace materiálu modulu

Obvyklá reprezentace takových polí je tabulky hodnoty obsahující informace linky A sloupců. Chcete-li definovat jeden prvek tabulky, musíte zadat dva indexy: první (podle konvence) určuje číslo řádku a druhý (opět podle konvence) určuje číslo sloupce.

Obrázek znázorňuje dvourozměrné pole A. Pole obsahuje tři řádky a čtyři sloupce, takže se také říká, že jde o pole tři na čtyři. Obecně platí, že pole s m linky a n sloupce se nazývají pole m na n.

Každý prvek v poli A určeno názvem prvku ve formuláři A[ i ][ j ]; A toto je název pole a i A j– indexy, které jednoznačně identifikují každý prvek v A. Všimněte si, že názvy prvků prvního řádku mají první index 0 , názvy prvků ve čtvrtém sloupci mají druhý index 3 .

Typická chyba programování

Neplatný odkaz na prvek dvourozměrného pole A[ X] [ y] Jak A[ X, y]. Ve skutečnosti, A[ X, y] vnímán jako A[ y] , protože C vyhodnocuje výraz (obsahující operaci čárky) X, y stejně jako y(poslední z výrazů oddělených čárkou).

Vícerozměrná pole lze inicializovat ve svých deklaracích stejně jako přirozeně indexovaná pole. Například dvourozměrné pole b můžete deklarovat a dát mu počáteční hodnoty takto:

int b = ((1,2), (3,4));

Hodnoty jsou seskupeny do řetězců uzavřených ve složených závorkách. Takže prvky b A b obdrží počáteční hodnoty 1 a 2 a prvky b A b získat počáteční hodnoty 3 a 4. Pokud počáteční hodnoty v daném řádku nestačí k jejich přiřazení ke všem prvkům řádku, pak zbývajícím prvkům jsou přiřazeny nulové počáteční hodnoty. Takže oznámení

int b = ((1,), (3,4));

to bude znamenat b získá počáteční hodnotu 1, b dostane počáteční hodnotu 0.

Množství paměti v bajtech obsazené dvourozměrným polem se vypočítá pomocí následujícího vzorce:

Počet bajtů = velikost 1._dimenze*velikost_2.rozměru*velikost (základní typ)

Například dvourozměrné pole 4bajtových celých čísel s rozměry 10*5 zabírá paměťovou oblast

tedy 200 bajtů.

Předání pole funkci.

Zvažte malý program pro zobrazení prvků dvourozměrného pole:

#zahrnout

void printArray(int a)

for (int i = 0; i<=1;i++)

for (int j=0; j<=2; j++)

printf(“%i, ”,&a[i][j]);

printf(“\n”);

int pole = ((1,2,3),(4,5,6));

printf(“Hodnoty v poli na řádcích:”);

printgArray(pole);

Hodnoty v poli na řádcích:

Program volá funkci printArray k zobrazení prvků pole. Všimněte si, že popis funkce specifikuje parametr pole jako intA. Když zadáme jednorozměrné pole jako argument funkce, závorky v seznamu parametrů funkce jsou prázdné. Dimenze prvního indexu vícerozměrného pole také není vyžadována, ale jsou vyžadovány všechny následující dimenze indexu. Kompilátor používá rozměry těchto indexů k určení vhodných paměťových míst pro přístup k prvkům vícerozměrných polí. V paměti jsou všechny prvky pole uloženy sekvenčně, bez ohledu na počet indexů (velikost pole). Ve dvourozměrném poli je první řádek uložen v paměti před druhým řádkem.

Mít rozměry indexu v deklaraci parametru umožňuje kompilátoru sdělit funkci, jak jsou prvky uspořádány v poli. Ve dvourozměrném poli je každý řádek jednorozměrným polem. Aby funkce našla prvek v nějakém řádku, musí přesně vědět, kolik prvků je v každém řádku. Poté může funkce při přístupu k poli přeskočit odpovídající počet paměťových buněk. Tedy při přístupu A Funkce ví, že pro přístup k druhému řádku (řádek 1) potřebuje přeskočit tři prvky prvního řádku v paměti a poté přistoupit ke třetímu prvku tohoto řádku (prvek 2).

Mnoho běžných operací pole používá konstrukci pro. Následující smyčka tedy určuje součet všech prvků pole A:

pro (řádek = 0; řádek< 3; row++)

for (sloupec = 0; sloupec< 3; column ++)

celkem += a ;

Vnitřní struktura pro sečte prvky jednoho řádku pole. Vnější struktura pro začíná instalací řádek(tj. index řádku) na nulu, takže ve vnitřní struktuře pro Prvky druhé řady lze sečíst. Další je vnější struktura pro zvyšuje řádek na hodnotu 2, aby bylo možné sečíst prvky třetího řádku. Po dokončení vnořené struktury pro vytiskne se výsledek.

Úkol

Studenti jedné z univerzit se jednou hádali o to, kdo má nejvyšší průměrné skóre za sezení, které právě absolvovali. Zároveň chtěli zjistit, kdo dostal nejlepší a nejhorší známky. Pro zajímavost si představme, že žijeme v Americe a hodnocení se udává na 100bodové škále.

Poznámka:

Program musí „znat“ jména studentů a zobrazovat je na obrazovce. To samé s vysvědčením. Předpokládá se, že čísla sloupců jsou ekvivalentní číslům zkoušek.

Úvahy o řešení problému

Nejprve si určíme, co potřebujeme k vyřešení tohoto problému. První věc, které si všimneme, je, že podmínka výslovně říká slovo „stůl“. To znamená, že s největší pravděpodobností k práci s ním použijeme dvourozměrné pole. Každý řádek v něm je výkonem jednotlivého studenta. Jak je uvedeno v podmínce, číslo sloupce určí číslo složené zkoušky, číslo řádku student. S tímto polem budeme pracovat a počítat průměrné skóre, minimum a maximum. Je vidět, že bude nutné vytvořit tři funkce pro získání potřebných dat a funkci pro zobrazení tabulky hodnocení na obrazovce. Již víme vše potřebné k napsání této části programu.

Nyní se podíváme na jména. Bylo by dobré je uspořádat do tabulky tak, aby číslo studenta mohlo být použito k určení jeho jména a naopak. Už víme. Že řetězec je jednorozměrné pole znaků. To znamená, že můžete vytvořit dvourozměrné pole, ve kterém číslo řádku určí číslo studenta a číslo sloupce bude určovat odpovídající písmeno jména. Pak ale budete muset vytvořit pole s co největším počtem horizontálních buněk. To znamená, že pokud máme čtyři studenty:

Poté budete muset vytvořit tabulku podobnou té, která je znázorněna na obrázku:


Prázdné buňky našeho pole jsou na obrázku zobrazeny šedě. Těmto buňkám bude přiděleno místo v paměti, ale nebudou využity. Proč je tedy potřebujeme? Existuje způsob, jak se této situaci vyhnout? Ukazuje se, že existuje. To bude probráno níže a poté se vrátíme k řešení našeho problému.

Při řešení problémů s velkým množstvím dat stejného typu ztěžuje programování použití proměnných s různými názvy, které nejsou seřazeny podle adres paměti. V takových případech jazyk C používá objekty zvané pole.

je souvislý kus paměti obsahující posloupnost objektů stejného typu, označených jedním jménem.

Pole se vyznačuje následujícími základními pojmy:

Element pole (hodnota elementu pole)– hodnota uložená ve specifické paměťové buňce umístěné v poli, stejně jako adresa této paměťové buňky.
Každý prvek pole je charakterizován třemi hodnotami:

  • adresa prvku - adresa počáteční paměťové buňky, ve které se tento prvek nachází;
  • index prvku (řadové číslo prvku v poli);
  • hodnota prvku.

Adresa pole – adresa počátečního prvku pole.

Název pole je identifikátor používaný k odkazování na prvky pole.

Velikost pole – počet prvků pole

Velikost prvku je počet bajtů obsazených jedním prvkem pole.

Graficky lze umístění pole v paměti počítače znázornit jako souvislý pruh adres.

Pole zobrazené na obrázku obsahuje q prvků s indexy od 0 do q-1. Každý prvek zabírá v paměti počítače k ​​bajtů a uspořádání prvků v paměti je sekvenční.

Adresy i-tého prvku pole jsou

Adresa pole je adresa počátečního (nulového) prvku pole. Pro přístup k prvkům pole se používá sériové číslo (index) prvku, jehož počáteční hodnota je 0. Pokud tedy pole obsahuje q prvků, pak se indexy prvků pole mění od 0 do q-1.

Délka pole je počet bajtů přidělených v paměti pro uložení všech prvků pole.

Délka pole = Velikost prvku * Počet prvků

Funkci lze použít k určení velikosti prvku pole

int sizeof(type);

Například,

sizeof(char) = 1;
sizeof(int) = 4;
sizeof(float) = 4;
sizeof(double) = 8;

Deklarace a inicializace polí

K deklaraci pole v C se používá následující syntaxe:

zadejte jméno[rozměr]=(init);

Inicializace je sada počátečních hodnot prvků pole, zadaných ve složených závorkách, oddělených čárkami.

int a = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9); // pole a o 10 celých číslech

Pokud je počet inicializačních hodnot zadaných ve složených závorkách menší než počet prvků pole zadaný v hranatých závorkách, pak všechny zbývající prvky v poli (pro které nebyl dostatek inicializačních hodnot) budou nulové. Tuto vlastnost je vhodné použít k nastavení všech prvků pole na nulové hodnoty.

int b = (0); // pole b z 10 prvků inicializováno na 0


Pokud je pole při deklaraci inicializováno, jsou konstantní počáteční hodnoty jeho prvků uvedeny oddělené čárkami ve složených závorkách. V tomto případě lze počet prvků v hranatých závorkách vynechat.

int a = (1, 2, 3, 4, 5, 6, 7, 8, 9);

Při přístupu k prvkům pole je index požadovaného prvku uveden v hranatých závorkách.

Příklad v C

1
2
3
4
5
6
7
8

#zahrnout
int main()
{
int a = (5, 4, 3, 2, 1); // pole a obsahuje 5 prvků
printf("%d %d %d %d %d\n" , a, a, a, a);
getchar();
návrat 0;
}

Výsledek spuštění programu:

Často je však nutné nastavit hodnoty prvků pole během provádění programu. To používá deklaraci pole bez inicializace. V tomto případě je uvedení počtu prvků v hranatých závorkách povinné.

int a;

K nastavení počátečních hodnot prvků pole se velmi často používá parametrická smyčka:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18


#zahrnout
int main()
{
int a;
int i;
// Zadání prvků pole
pro (i = 0; i<5; i++)
{
printf("a[%d] = " , i);
scanf("%d" , &a[i]);
}
// Výstup prvků pole
pro (i = 0; i<5; i++)
printf("%d" , a[i]); // je vyžadováno místo ve formátu tisku
getchar(); getchar();
návrat 0;
}

Výsledek spuštění programu

Vícerozměrná pole

Vícerozměrná pole lze také deklarovat v C. Rozdíl mezi vícerozměrným polem a jednorozměrným je v tom, že v jednorozměrném poli je poloha prvku určena jedním indexem a ve vícerozměrném poli několika. Příkladem vícerozměrného pole je matice.

Obecná forma deklarace vícerozměrného pole

název typu[rozměr1][rozměr2]...[rozměr];

Prvky vícerozměrného pole jsou umístěny v po sobě jdoucích buňkách RAM ve vzestupném pořadí adres. V paměti počítače jsou prvky vícerozměrného pole uspořádány v řadě, například pole se 2 řádky a 3 sloupci,

int a;


budou umístěny v paměti následovně

Celkový počet prvků v daném dvourozměrném poli je určen jako

Počet řádků * Počet sloupců = 2 * 3 = 6.

Počet bajtů paměti potřebné k umístění pole je dán

Počet položek * Velikost položky = 6 * 4 = 24 bajtů.

Inicializace vícerozměrných polí

Hodnoty prvků vícerozměrného pole, jako v jednorozměrném případě, mohou být specifikovány konstantními hodnotami, když jsou deklarovány, uzavřené ve složených závorkách (). V tomto případě však musí být počet prvků v řádcích a sloupcích uveden v hranatých závorkách.

Příklad v C

1
2
3
4
5
6
7
8
9

#zahrnout
int main()
{
int a = (1, 2, 3, 4, 5, 6);
printf("%d %d %d\n" , a, a, a);
getchar();
návrat 0;
}



Častěji je však nutné zadávat hodnoty prvků vícerozměrného pole během provádění programu. Pro tento účel je vhodné použít vnořenou parametrickou smyčku.

Příklad v C

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

#define _CRT_SECURE_NO_WARNINGS
#zahrnout
int main()
{
int a; // pole 2 řádků a 3 sloupců
int i, j;
// Zadání prvků pole
pro (i = 0; i<2; i++) // procházet řádky
{
pro (j = 0; j<3; j++) // procházet sloupce
{
printf("a[%d][%d] = " , i, j);
scanf("%d" , &a[i][j]);
}
}
// Výstup prvků pole
pro (i = 0; i<2; i++) // procházet řádky
{
pro (j = 0; j<3; j++) // procházet sloupce
{
printf("%d " , a[i][j]);
}
printf("\n" ); // nový řádek
}
getchar(); getchar();
návrat 0;
}



Předání pole funkci

Zpracování pole lze pohodlně organizovat pomocí speciálních funkcí. Chcete-li zpracovat pole, musíte funkci předat jako argumenty

  • adresa pole,
  • velikost pole.

Výjimkou jsou funkce pro zpracování řetězců, kde stačí předat pouze adresu.

Při předávání proměnných jako argumentů funkci jsou data předána jako kopie. To znamená, že pokud se uvnitř funkce změní hodnota parametru, neovlivní to její hodnotu uvnitř volající funkce.

Pokud je funkci předána adresa proměnné (nebo adresa pole), pak se všechny operace prováděné ve funkci s daty v rozsahu zadané adresy provádějí s původními daty, takže lze původní pole (nebo hodnotu proměnné) změnit pomocí volané funkce.

Příklad v C Dan pole 10 prvků. Zaměňte největší a počáteční prvky pole. Pro maximální vyhledávání a výměnu prvků použijte funkci.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

#define _CRT_SECURE_NO_WARNINGS
#zahrnout
// Funkce výměny
void change(int *x, int n)
{
// x - ukazatel na pole (adresa pole)
// n - velikost pole
int i;
int max, index;
max = x;
index = 0;
// Nalezení maximálního prvku
pro (i = 1; i {
if (x[i]>max)
{
max = x[i];
index = i;
}
}
// Výměna
x = x;
x = max;
}
// Hlavní funkce
int main()
{
int a;
int i;
pro (i = 0; i<10; i++)
{
printf("a[%d] = " , i);
scanf("%d" , &a[i]);
}
změna(a, 10); // volání funkce exchange
// Výstup prvků pole
pro (i = 0; i<10; i++)
printf("%d " , a[i]);
getchar();
getchar();
vrátit se
p = p * x[i];
}
vrátit p;
}
// Hlavní funkce
int main()
{
int a; // deklarované pole a o 5 prvcích
int i;
int pr;
// Zadání prvků pole
pro (i = 0; i<5; i++)
{
printf("a[%d] = " , i);
scanf("%d" , &a[i]); // &a[i] - adresa i-tého prvku pole
}
pr = func(a, 5); // vypočítat součin
printf("\n pr = %d" , pr); // výstup součinu sudých prvků
getchar(); getchar();
návrat 0;
}






Horní