Проблема с выделением памяти вне основной

Будучи новичком в C, я научился причудливому способу выделения памяти с помощью struct{}, чтобы заменить что-то вроде ch1Buffer = calloc(u32Size, sizeof *ch1Buffer); и поместить их вне int main{}, чтобы повысить скорость вычислений. Однако я получил ошибку в моей переменной x, говоря: This declaration has no storage class or type specifier, вы можете увидеть аннотацию сбоку от кода. Должен ли я объявить переменную x или?

Вот мой пример кода:

#include <stdio.h>

// New way for memory allocation 
struct {
    float ch1Buffer;
    double ch2Buffer;
    double ch2newBuffer;
} *x;
x = calloc(10, sizeof * x); // The error happened on the left side "x": This declaration has no storage class or type specifier

int main()
{
    int i,n;
    const int u32Size = 10;
    float* ch1Buffer = NULL;
    double* ch2Buffer = NULL;
    double* ch2newBuffer=NULL;
    
    
    int pBuffer[] = { 10,2,10,2,10,5,10,5,10,2 };
    int* pi16Buffer = pBuffer;

    // Old way for memory allocation
    //ch1Buffer = (float*)calloc(u32Size, sizeof* ch1Buffer);
    //ch2Buffer = (double*)calloc(u32Size, sizeof* ch2Buffer);
    //ch2newBuffer = (double*)calloc(u32Size, sizeof * ch2Buffer);

    

    // De-interveal the data to ch1Buffer and ch2Buffer
    for (i = 0; i < u32Size/2; i++)
    {
        ch1Buffer[i] += pi16Buffer[i * 2];
        ch2Buffer[i] += pi16Buffer[i * 2 + 1];
    }

    // Use memcpy to pick out the data we are interested
    memcpy(ch2newBuffer, &ch2Buffer[2], 2 * sizeof(ch2Buffer[0]));

    for (i = 0; i < 2; i++)
    {
        printf("a[%d] = %f\n", i, *ch2newBuffer);
        ch2newBuffer++;
    }


    free(ch1Buffer);
    free(ch2Buffer);
    return 0;
}

Вы не можете вызывать функции при инициализации глобальных переменных в C.

Jabberwocky 22.12.2020 17:45

@Jabberwocky Но даже я поставил struct{} внутри основного, произошла другая ошибка: a value of type "void*" cannot be assigned to an entity "struct<unnamed>*"

Kevin 22.12.2020 17:52

Ты не сможешь это сделать. Ни C, ни C++ так не работают. Что касается более поздней ошибки компиляции - это потому, что вы компилируете код как C++, но на самом деле вы пишете код C. C++ требует явного приведения из void *, которое возвращает функция C calloc. C и C++ - два совершенно разных языка. Если вы хотите написать код на C, используйте компилятор C. Если вы намерены изучать и писать на C++, забудьте о calloc, printf и других и вместо этого используйте безопасные с точки зрения типов эквиваленты C++, дополнительную информацию см. в учебнике по C++.

Sam Varshavchik 22.12.2020 17:53

@Кевин, тебе нужно #include <stdlib.h> для calloc. Но это похоже на другой вопрос. Задайте новый вопрос для этого.

Jabberwocky 22.12.2020 17:55

Я голосую за то, чтобы закрыть этот вопрос, потому что он показывает, что ОП не предпринял никаких усилий для самостоятельного решения проблем.

user3629249 23.12.2020 03:56
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
5
297
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Вы не можете выполнять malloc или calloc вне основной или любой другой функции. Вы можете объявить его в начале своего кода, если он вам нужен как глобальная переменная, но вам нужно будет выделить память, например, внутри основного.

typedef struct mystruct {
  float ch1Buffer;
  double ch2Buffer;
  double ch2newBuffer;
}mystruct;

mystruct* x;

int main (void) {
    x = calloc(10, sizeof(mystruct)); // array of your structs
    if (!x) { // always check calloc return value
        perror("calloc");
        exit(EXIT_FAILURE);
    }

    /* do stuff */

    return 0;
}

Кроме того, я бы предложил давать понятные имена вашим структурам для лучшего понимания того, что они представляют.

Спасибо! Но я все еще получаю ошибку в строке x = calloc(10, sizeof(mystruct));, говоря ErroC2440'=': cannot convert from 'void *' to 'mystruct *'

Kevin 23.12.2020 13:25

Это распространенная ошибка компилятора, просто добавьте это перед calloc: x = (mystruct*)calloc(10, sizeof(mystruct));. Явное приведение calloc к типу вашей переменной, в данном случае это mystruct*, должно было решить вашу проблему. Это хорошая привычка всегда делать это приведение для malloc, calloc, потому что некоторые компиляторы не запускаются.

Matteo Pinna 23.12.2020 13:35

Спасибо, но здесь возникает проблема, с которой я сталкивался раньше при использовании struct{} для выделения памяти. Ошибка произошла в De-interveal части, ch1Buffer[i] += pi16Buffer[i * 2]; говоря, Exception thrown at 0x00007FF719D41A9B in Examplefordebug.exe: 0xC0000005: Access violation reading location 0x0000000000000000. похоже, что память не была успешно выделена?

Kevin 23.12.2020 13:44

На самом деле, я пытаюсь имитировать обработку данных, когда моя DAQ-карта получает данные по каналу 1 и каналу 2. Правило заполнения данных в памяти: ch1ch2ch1ch2.... Поэтому я написал цикл for для разделения ' и получите эти два канала от pi16Buffer[i]. Может быть, лучший подход для такого распределения памяти?

Kevin 23.12.2020 14:22

Задайте еще один вопрос о новой проблеме, с которой вы столкнулись. Я не уверен, что смогу помочь вам с этим, использование calloc в любом случае нормально, проблема больше не связана с его использованием. Надеюсь, моя помощь была полезной для первой части в любом случае :)

Matteo Pinna 23.12.2020 14:34

Спасибо! Я отдал тебе должное! По крайней мере, я подтвердил, что не ошибся при использовании struct{}

Kevin 23.12.2020 14:47

Это дает вам пример использования компонентов каждого члена. Как и в приведенных выше ответах, указатель определяется как глобальный и размещается в main(). Это не очень хорошая практика, просто для демонстрации.

#include <stdio.h>
#include <stdlib.h>
#define SIZE 10
struct xxx {
    float f1;
    double d2;
    double d3;
};
typedef struct xxx mytype;
mytype *x;
void print_mytype()
{
    int i;
    for (i=0; i<SIZE; i++) printf("x[%d] = %f, %lf, %lf\n", i, x[i].f1, x[i].d2, x[i].d3);
    return;
}
void setdata()
{
    int i;
    for (i=0; i<SIZE; i++)
    {
      x[i].f1 = rand()/(float)RAND_MAX;
      x[i].d2 = rand()/(double)RAND_MAX;
      x[i].d3 = rand()/(double)RAND_MAX;
    }
}
int main()
{
    x = calloc(SIZE, sizeof(mytype));
    setdata();
    print_mytype();
    free(x);
    return 0;
}

размещенный код не компилируется!

Вот что компилятор говорит о коде:

gcc -ggdb3 -Wall -Wextra -Wconversion -pedantic -std=gnu11 -c "untitled1.c" -o "untitled1.o" 
untitled1.c:9:1: warning: data definition has no type or storage class
    9 | x = calloc(10, sizeof * x); // The error happened on the left side "x": This declaration has no storage class or type specifier
      | ^
      
untitled1.c:9:1: warning: type defaults to ‘int’ in declaration of ‘x’ [-Wimplicit-int]

untitled1.c:9:1: error: conflicting types for ‘x’

untitled1.c:8:4: note: previous declaration of ‘x’ was here
    8 | } *x;
      |    ^
      
untitled1.c:9:5: warning: implicit declaration of function ‘calloc’ [-Wimplicit-function-declaration]
    9 | x = calloc(10, sizeof * x); // The error happened on the left side "x": This declaration has no storage class or type specifier
      |     ^~~~~~
      
untitled1.c:9:5: warning: incompatible implicit declaration of built-in function ‘calloc’

untitled1.c:2:1: note: include ‘<stdlib.h>’ or provide a declaration of ‘calloc’
    1 | #include <stdio.h>
  +++ |+#include <stdlib.h>
    2 |
    
untitled1.c:9:23: error: invalid type argument of unary ‘*’ (have ‘int’)
    9 | x = calloc(10, sizeof * x); // The error happened on the left side "x": This declaration has no storage class or type specifier
      |                       ^~~
      
untitled1.c: In function ‘main’:

untitled1.c:33:22: warning: conversion from ‘int’ to ‘float’ may change value [-Wconversion]
   33 |         ch1Buffer[i] += pi16Buffer[i * 2];
      |                      ^~
      
untitled1.c:38:5: warning: implicit declaration of function ‘memcpy’ [-Wimplicit-function-declaration]
   38 |     memcpy(ch2newBuffer, &ch2Buffer[2], 2 * sizeof(ch2Buffer[0]));
      |     ^~~~~~
      
untitled1.c:38:5: warning: incompatible implicit declaration of built-in function ‘memcpy’

untitled1.c:2:1: note: include ‘<string.h>’ or provide a declaration of ‘memcpy’
    1 | #include <stdio.h>
  +++ |+#include <string.h>
    2 |
    
untitled1.c:47:5: warning: implicit declaration of function ‘free’ [-Wimplicit-function-declaration]
   47 |     free(ch1Buffer);
      |     ^~~~
      
untitled1.c:47:5: warning: incompatible implicit declaration of built-in function ‘free’

untitled1.c:47:5: note: include ‘<stdlib.h>’ or provide a declaration of ‘free’

untitled1.c:13:11: warning: unused variable ‘n’ [-Wunused-variable]
   13 |     int i,n;
      |           ^
      
Compilation failed.

Предложите вам исправить те проблемы в коде, которые вы можете, прежде чем спрашивать нас о каких-либо проблемах, которые вы не можете исправить.

Как говорится в сообщениях об ошибках:

  1. добавить заявление:

    #include <stdlib.h>

  2. добавить заявление:

    #include <string.h>

Мы вряд ли поможем вам, когда код, который вы публикуете, ясно указывает на то, что вы не приложили никаких усилий для решения проблемы (проблем) самостоятельно.

Спасибо за ваш совет, кроме того, если вы думаете, что я не приложил никаких усилий, вы можете решить не отвечать или беспокоить;)

Kevin 23.12.2020 13:27

@Kevin, когда вы публикуете код, который не показывает никаких усилий (с вашей стороны), вы будете отмечены и увидите комментарии о «никаких усилиях». Предложите: исправьте те вещи, которые вы можете, например, отсутствующие файлы заголовков, а затем опубликуйте раздел «редактирование» в своем вопросе.

user3629249 23.12.2020 18:38

Другие вопросы по теме