1

Тема: Вказівник на рядок в двохвимірному масиві

Оголошено двовимірний масив:

uint16_t buffVal[4][32];

4 рядки, а в рядку по 32 uint16_t. А по суті це 128 комірок для uint16_t
В циклі треба передати в функцію вказівник спочатку на 0 елемент масиву (це початок першого рядка двовимірного масиву), потім на 32 елемент (це початок другого рядка двовимірного масиву), потім на 64 елемент (третій рядок) і 96 елемент (четвертий рядок). А вже в функції обробити рядок з 32-х uint16_t.
Роблю так:
Функція:

uint16_t func(uint16_t *buff)
{
    uint tmp;
        
    for (int i = 0; i < 32; ++i)
    {
        tmp += buff[i];
    }

    return (uint16_t) tmp / 32;
}

Викликаю функцію так:

for (int i = 0; i < 4; ++i)
{
    dataFilterADC[i] = func(&buffVal[i][0]);
}

В мене є сумніви чи це є правильно. Сумніви і по передачі вказівника у функцію на початок даних які потрібно обробити і сумніви щодо перебору елементів масиву в самій функції.
Гуглив, читав, всеодно не розумію. Мені вказівники дуже складно даються. Допоможіть будь ласка.

2

Re: Вказівник на рядок в двохвимірному масиві

Ну якщо не можна використовувати std, то я б викликав так:

for (int i = 0; i < 4; ++i)
{
    dataFilterADC[i] = func(buffVal[i]);
}
Подякували: leofun01, taburyak2

3 Востаннє редагувалося taburyak (19.07.2018 17:05:52)

Re: Вказівник на рядок в двохвимірному масиві

Yola написав:

Ну якщо не можна використовувати std, то я б викликав так:

for (int i = 0; i < 4; ++i)
{
    dataFilterADC[i] = func(buffVal[i]);
}

Я наче здогадуюсь що ви маєте на увазі. Але в мене досвіду не вистачає переробити параметри функції до відповідності:

Компілятор свариться -
"Description    Resource    Path    Location    Type
passing argument 1 of 'func' from incompatible pointer type [-Wincompatible-pointer-types]    main.c"
   
"expected 'uint16_t * {aka short unsigned int *}' but argument is of type 'uint16_t (*)[32] {aka short unsigned int (*)[32]}'"

Підкажіть як змінити параметр buff?  uint16_t func(uint16_t* buff)

4

Re: Вказівник на рядок в двохвимірному масиві

uint16_t func(uint16_t buff[32])

Однак у коді фіксовано 32.
До речі, все одно використовується щонайменше C99, то можна так

uint16_t func(uint16_t len, uint16_t buff[len])

з викликом

dataFilterADC[i] = func(32, buffVal[i]);

скрізь у коді 32 замінити на len і мати універсальну функцію.
Хоча тоді ділення буде діленням, а не зсувом, як для 32.

Подякували: leofun01, taburyak2

5

Re: Вказівник на рядок в двохвимірному масиві

До речі, всяка MISRA буде щаслива.

Прихований текст

Спитали тут нещодавно: «Чи знайомі Ви з MISRA»
Відповів: «Чув про таке, навіть зазирав. Але я дуже люблю вказівники, а MISRA їх дуже не любить. Тому, оскільки обов'язку використовувати не було, далеко не заглиблювався»

Подякували: taburyak1

6 Востаннє редагувалося taburyak (20.07.2018 21:22:53)

Re: Вказівник на рядок в двохвимірному масиві

Всім дякую.
Наче працює коректно в такому вигляді:

uint16_t func(uint16_t* buff[chanel])

та виклик:

dataFilterADC[i] = func(buffVal[i]);

to ReAl: 32 то так для прикладу. Там в мене це значення в дефайнах. Універсальна не потрібна.

7

Re: Вказівник на рядок в двохвимірному масиві

Так, трохи звільнився.
По перше

return (uint16_t) tmp / 32;

неправильно. Воно спочатку приведе tmp до uint16_t, а потім поділить. Буде втрачено старшу частину суми.
Тобто треба б

return (uint16_t)(tmp / 32);

але це потрібно хіба що якщо компілятор викидає попередження на автоматичне приведення з ширшого типу до вужчого «можуть пропасти розряди», а ручним приведенням це попередження знімається.
Інакше досить просто

return tmp / 32;

А зайві літери лише провокують помилки.

Подякували: taburyak1

8

Re: Вказівник на рядок в двохвимірному масиві

Тепер про прототип функції. Щось я не розумію, який компілятор і на що лаявся.

#include <stdint.h>

uint16_t dataFilterADC[4];
uint16_t buffVal[4][32];

uint16_t func(uint16_t *buff)  // (1)
//uint16_t func(uint16_t buff[32]) // (2)
//uint16_t func(uint16_t *buff[32]) // (3)
{
    uint32_t tmp = 0;
                            
    for (int i = 0; i < 32; ++i) {
        tmp += buff[i];
    }
    return (uint16_t) tmp / 32;
}

void moo()
{
    for (int i = 0; i < 4; ++i) 
        dataFilterADC[i] = func(buffVal[i]);
}

$ linaro-cm3 -Wincompatible-pointer-types -S arr.c

(1) - OK
(2) - OK
(3) -

arr.c: In function ‘func’:
arr.c:13:7: warning: assignment makes integer from pointer without a cast [-Wint-conversion]
   tmp += buff[i];
       ^~
arr.c: In function ‘moo’:
arr.c:21:27: warning: passing argument 1 of ‘func’ from incompatible pointer type [-Wincompatible-pointer-types]
   dataFilterADC[i] = func(buffVal[i]);
                           ^~~~~~~
arr.c:8:10: note: expected ‘uint16_t ** {aka short unsigned int **}’ but argument is of type ‘uint16_t * {aka short unsigned int *}’
 uint16_t func(uint16_t *buff[32]) // (3)
          ^~~~

linaro-cm3 це я для простоти такий скриптик зліпив
/opt/gcc-linaro-7.2.1-2017.11-x86_64_arm-eabi/bin/arm-eabi-gcc -mcpu=cortex-M3 -mthumb $*
бо його у мене зараз у PATH нема.

Подякували: taburyak1

9

Re: Вказівник на рядок в двохвимірному масиві

ReAl написав:

А зайві літери лише провокують помилки.

Дякую за цінні поради, взяв до уваги.

ReAl написав:

Щось я не розумію, який компілятор і на що лаявся.

А тут я не зрозумів. Перепрошую.

10

Re: Вказівник на рядок в двохвимірному масиві

По-перше, двовимірних масивів в C не існує. Є масиви масивів.
По-друге, не використовуйте "магічні числа", використовуйте константи.
По-третє, зі складними типами легше працювати, якщо проголошувати проміжні типи.

А тепер дивимося:

#define ROW_LENGTH 32
#define ROW_COUNT 4

typedef uint16_t Row[ROW_LENGTH]; //рядок

Row buffVal[ROW_COUNT];

uint16_t func(Row *buff) //те саме, що й uint16_t func(uint16_t buff[ROW_LENGTH]) або uint16_t func(uint16_t *buff[ROW_LENGTH]), але наочніше
{
    uint16_t tmp;
        
    for (int i = 0; i < ROW_LENGTH; ++i)
    {
        tmp += buff[i];
    }
 
    return tmp / ROW_LENGTH; // для цілих / дає цілий результат
}

...
uint16_t dataFilterADC[ROW_COUNT];
for (int i = 0; i < ROW_COUNT; ++i)
{
    dataFilterADC[i] = func(buffVal[i]);
}
  
Подякували: taburyak1

11

Re: Вказівник на рядок в двохвимірному масиві

koala написав:

По-третє, зі складними типами легше працювати, якщо проголошувати проміжні типи.

А тепер дивимося:

Велике дякую.
Оце так-так! Таким способом дуже зрозуміло і не плутаюсь. Те що треба.

12

Re: Вказівник на рядок в двохвимірному масиві

"Дякую" - це дієслово 1 особи (інфінітив - "дякувати"), і великим, відповідно, бути не може. Поріняйте "рубаю", "ходжу", "читаю" - як це "велике читаю"? Можна щиро дякувати, повільно рубати, швидко ходити, читати навкіс - коротше, тут потрібен прислівник, а не прикметник.

Подякували: NaharD1

13

Re: Вказівник на рядок в двохвимірному масиві

дуже дякую мо?

14

Re: Вказівник на рядок в двохвимірному масиві

Питання третє: ЯК ми висловлюємо подяку?

Правильно вживати такі слова: «Красно дякую», «Щиро дякую», «Сердечно дякую» чи «Дуже Вам дякую». Звичайно, ця форма має відповідати змісту подяки.

Інший варіант подяки – «Спасибі» (традиційно вважається, що його більше використовують на Півдні та Сході України). Один з найкращих варіантів – «Сердечне спасибі».

ОБЕРЕЖНО: русизм – «Велике спасибі».

Запам’ятаймо, що в українській мові такого вислову немає, це копія з російської мови.

http://school22.com.ua/index.php/predme … -dyakuvati

Подякували: taburyak1

15

Re: Вказівник на рядок в двохвимірному масиві

koala, щиро дякую ;)