21

Re: Сішка, непередбачувана поведінка

Torbins написав:
Q-bart написав:

Як це пояснювати можна? Або гуглити, бо щось нічого толкового не знайшов))

Ось хороша стаття: Неочевидные особенности вещественных чисел, щоправда російською.

О, дякую! Перегляну!

22

Re: Сішка, непередбачувана поведінка

І знову я тут  :)

Сішка цікава. РОзкажіть мені будь ласка, чому якщо я виділяю памяті під 4 елементи масиву, я отримую масив з довжиною 2?
What`s the hell?

#include "stdio.h"
#include "malloc.h"

int main(int argc, char const *argv[])
{
    int size = 4;

    int * array = (int * )malloc(size * sizeof(int)); 
    printf("Len of array: %li \n", sizeof(array) / sizeof(int));
    return 0;
}
OUT:
Len of array: 2 

23

Re: Сішка, непередбачувана поведінка

Воно так не робе, натомість робе так:

int a[17];
n = sizeof(a)/sizeof(a[0]);
Подякували: Q-bart, leofun012

24

Re: Сішка, непередбачувана поведінка

Тому, що маєте 64-бітну машину систему, мали б 32-бітну, було б 1  :D
Це якщо коротко (другу сторону цього «коротко» описав 0xDADA11C7).

Якщо довго — забудьте поширену помилку «ім'я масиву еквівалентне вказівнику на перший його елемент»
І тим більше ніколи не вважайте, що «вказівник на перший елемент масиву еквівалентний його…» ммм… designator
Бо в операторі sizeof можна використовувати лише оцей designator, яким є ім'я масиву в нотації type array[size].
Для int *array оператор sizeof дав розмір вказівника, 8 байтів для 64-бітної системи, після дялення на розмір int (4) вийшло оті 2.

Подякували: Q-bart, 0x9111A, varkon, leofun014

25 Востаннє редагувалося Q-bart (06.11.2017 16:52:07)

Re: Сішка, непередбачувана поведінка

0xDADA11C7 написав:

Воно так не робе, натомість робе так:

int a[17];
n = sizeof(a)/sizeof(a[0]);

Ой! Не паше)

UPD.
Вірніше не паше з вказівником

26

Re: Сішка, непередбачувана поведінка

ReAl написав:

Тому, що маєте 64-бітну машину систему, мали б 32-бітну, було б 1  :D
Це якщо коротко (другу сторону цього «коротко» описав 0xDADA11C7).

Якщо довго — забудьте поширену помилку «ім'я масиву еквівалентне вказівнику на перший його елемент»
І тим більше ніколи не вважайте, що «вказівник на перший елемент масиву еквівалентний його…» ммм… designator
Бо в операторі sizeof можна використовувати лише оцей designator, яким є ім'я масиву в нотації type array[size].
Для int *array оператор sizeof дав розмір вказівника, 8 байтів для 64-бітної системи, після дялення на розмір int (4) вийшло оті 2.

А як отримати мені там 4?

27

Re: Сішка, непередбачувана поведінка

p.s.

стандарт С написав:

Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined.

Тобто ім'я масиву автоматично приводиться до вказівника на його перший елемент практично в усіх ситуаціях, тому складається враження, що воно еквівалентне до цього вказівника і тому доволі часто пробують цю (відсутню) «еквівалентність» повернути в інший бік і запхати вказівник на я_знаю_що_там_масив під sizeof.

Подякували: 0xDADA11C7, Q-bart, leofun013

28

Re: Сішка, непередбачувана поведінка

Якісь тут пояснення такі що навіть мене заплутали.

Вказівник на масив займає вдвічі більше ніж int, бо це просто вказівник і йому треба стільки байт скільки треба аби записати адресу. C - не python, тут масиви про свою довжину не знають, її програміст має записати десь окремо. (або не записувати, а просто після останнього елемента чимось позначити кінець, як от в сішних рядках

Подякували: Q-bart, leofun012

29

Re: Сішка, непередбачувана поведінка

Q-bart написав:

А як отримати мені там 4?

Тільки так, яка показав 0xDADA11C7.
Зі «справжнім» масивом.
Бо таки ж

Q-bart написав:

Вірніше не паше з вказівником

бо воно показує розмір вказівника.

Подякували: Q-bart1

30

Re: Сішка, непередбачувана поведінка

Оця та ваша сішка! Нащо вона здалась, був у мене python класний, треба було мені йти в той універ!

P.S. Все ок. Пішов вчитись, Треба було поскиглиити

31 Востаннє редагувалося ReAl (06.11.2017 17:23:11)

Re: Сішка, непередбачувана поведінка

ReAl написав:
Q-bart написав:

А як отримати мені там 4?

Тільки так, яка показав 0xDADA11C7.
Зі «справжнім» масивом.

Ніколи не кажи ніколи™
Можна ще зі вказівником на справжній масив :-)

С99 і пізніше для a[не-константа]

Якось так:

#include <stdio.h>
#include <stdlib.h>


void foo(int i)
{
        int a[i];
        int n = sizeof(a)/sizeof(a[0]);
        printf("i=%d, n=%d\n", i, n);
}

void moo(int i)
{
        // тут a вказівник не на int, а на масив int-ів
        int (*a)[i] = malloc(i * sizeof(int));
        int n = sizeof(*a)/sizeof((*a)[0]);
        printf("i=%d, n=%d\n", i, n);
        if (i > 1) {
                (*a)[1] = 3;
                printf("(*a)[1] = %d\n", (*a)[1]);
        }
        free(a);
}

int main()
{
        foo(12);
        foo(15);
        moo(12);
        moo(15);
}
Подякували: sensei1

32

Re: Сішка, непередбачувана поведінка

C не нав'язує майже нічого над те, що ви робите. Ви виділяєте пам'ять? Чудово, тепер - ваша і тільки ваша відповідальність стежити, щоб ваш код не виліз за її межі, і щоб ви її повернули, коли вона буде вам не потрібна. Ніяких чудес немає, malloc повертає вказівник і все. Більше нічого. Розміру немає, типу немає. Просто шмат пам'яті. Загубили вказівник - пам'ять тече. Переплутали, що хотіли в неї записати - втратили дані. Вилізли за межі - що завгодно, від читання 0 до падіння програми. Ніяких способів дізнатися, скільки раніше було виділено пам'яті, немає, окрім написаного вами обліку під час виділення. Так що

    int * array = (int * )malloc(size * sizeof(int)); 
    printf("Len of array: %li \n",/*єдиний спосіб дізнатися, скільки там int-ів*/ size);
Подякували: Q-bart, ReAl, leofun013

33

Re: Сішка, непередбачувана поведінка

Тада, розумію що тут все низькорівнево)

А що робить оце?

(int * )

Бо оце:

malloc(size * sizeof(int))

Це зрозуміло. Передаємо в функцію яку к-сть бітів треба мені виділити. А ось те що перед ним?

34 Востаннє редагувалося bunyk (06.11.2017 17:46:30)

Re: Сішка, непередбачувана поведінка

malloc просто повертає вказівник на якісь байти (здається void *). А коли його примусово перетворити на int *, то array++ буде зсувати його на стільки байт скільки займає int. А до того він не знає на скільки зсувати для наступного елемента

Подякували: koala, Q-bart, sensei, leofun014

35

Re: Сішка, непередбачувана поведінка

Перетворення типів в C позначається так:
(у_що_перетворюємо)що перетворюємо.
Наприклад, (int)5.3 == 5.
Трохи уточню, новачки в C часто пропускають цей момент з масивами. Хай ми маємо:

int a[10];//масив
int *pa=a;//вказівник
int b;//число

a майже завжди (крім sizeof) означає те саме. що й &a[0] - вказівник на початок пам'яті. І a[ b] - це те саме, що *(a+b). Тобто щоб отримати адресу b-го елементу з a, компілятор обчислює (int*)((int)a+b*sizeof(int)) (звісно, я тут розписую максимально детально, а у компілятора все це оптимізується і зайві дії викидаються). Зокрема, pa[ b]==a[ b], pa+b==a+b, p+1==a+1, інкременти і віднімання теж працюють так само. Звісно, інкрементувати a неможливо, a - вказівник на фіксоване місце в пам'яті, константа; але pa - легко.

Подякували: 0xDADA11C7, ReAl, Q-bart, leofun014

36 Востаннє редагувалося ReAl (06.11.2017 18:43:37)

Re: Сішка, непередбачувана поведінка

koala написав:
int a[10];//масив
int *pa=a;//вказівник
int b;//число

a майже завжди (крім sizeof) означає те саме. що й &a[0] - вказівник на початок пам'яті.

Ще крім &, тобто &a означатиме не &&a[0], а вказівник саме на масив (як і sizeof(a) показує розмір масиву), а змінна сумісного для даного прикладу типу int (*paa)[10] = &a; при інкременті відступатиме у пам'яті на 10 інтів (розмір масиву), а не на 1.

Подякували: Q-bart, koala, leofun013

37

Re: Сішка, непередбачувана поведінка

Оце класно! Дякую, за пояснення!

Насправді, мене збила з толку зірочка у (int *) - бо конвертування типів - я знаю))

38

Re: Сішка, непередбачувана поведінка

І ще одне питання)

Мені треба збирати в масив структури.  Звісно ж, що масив динамічний (ми не в садіку, щоб з статичним бавитись). Поскладав кілька структур в масив, обробив дані, і пішов на нову ітерацію циклу => мені знову туди треба поскладати об'єкти (не знаю як вірно буде) структур. Але ясно ж що перед цим треба почистити той масив.

while (1==1) {
        struct rib *incidental = malloc(0);  // оголошуємо масив об'єктів структур (поки нуль)

        /* Get all incidental ribs to used vertices */
        // щось робимо ........
        // бачимо що нам треба додати в масив новий елемент => додаєм до вже виділеної 
        // пам'яті трохи місця на один елемент. Додаємо сам елемент.........
                    incidental = (struct rib*)realloc(incidental, sizeof(struct rib));
                    incidental[i].from = i+1;

        // Далі ще щось робимо. Але тут цикл дійшов до закінчення ітерації. Нам треба звільнити це все від 
мотлоху.
        free(incidental);

        // пішли на наступну ітерацію і отримали *** Error in `./main': free(): invalid next size (fast): 
        // Якщо без free, то матюкається в такому випадку на realloc
    }

Коли не треба йти на другу ітерацію, то все класно працює. Тому звідси роблю виснвок, що десь в мене переповнення пам'яті, як казав koala

39

Re: Сішка, непередбачувана поведінка

Було б добре якби ви цикл до коду додали бо не дуже зрозуміло
В будьякому випадку, realloc не додає пам'яті а перевиділяє її. Тобто

void *p = realloc(NULL, 1);
void *p1 = realloc(p, 1); // p1 вказує на 1 байт (не на два)

40 Востаннє редагувалося koala (06.11.2017 22:07:28)

Re: Сішка, непередбачувана поведінка

Ви плутаєте проголошення і виділення пам'яті. Для змінних в купі це різні дії:

struct rib *incidental;//проголошення вказівника
incidental=(struct rib *)malloc(10*sizeof(struct rib));//виділення пам'яті, на яку тепер вказує наш вказівник

malloc(0), наскільки я пам'ятаю, implementation defined, тобто може повертати різні речі залежно від компілятора. Краще так не робити, а писати просто NULL.
Ну і крім усього іншого, malloc відносно повільний, ним краще користуватися не надто часто - тобто запитувати треба із запасом.

Втім, цей код не падає: https://ideone.com/pOi6Bi - а отже, ви викинули якусь суттєву частину, в якій і була помилка. Будь ласка, стежте, що надаєте саме код, який ілюструє ваше питання, а не іншу його частину. Телепатів тут нема.

До речі, а i у вас завжди 0? Якщо ні, то ви можете випадково переписувати якусь системну структуру даних, що й призводить до цієї помилки.

Подякували: Q-bart1