Как реализовать частоту pset3 в cs50 и понять notes.c - PullRequest
0 голосов
/ 03 июня 2018

У меня есть несколько вопросов о музыке CS50.

1) Есть строка for (int i = 0, n = sizeof(NOTES) / sizeof(string); i < n; i++) в notes.c.Что означает sizeof ( string )?Я могу понять sizeof (NOTES), здесь NOTES - это массив строк.Но что строка означает в sezeof ( строка )?Я не могу его получить.

2) Вот моя реализация "частоты":

int frequency(string note)
{
    char N[2];
    int octave;
       //parsing the string into a note...
    strncpy(N, note, (strlen(note) - 1));
    //...and its octave
    octave = note[strlen(note) - 1] - '0';
    //add semitones
    int semitone;
    if (strcmp(N, "C") == 0)
        semitone = 1;
    if (strcmp(N, "C#") == 0 || strcmp(N, "Db") == 0)
        semitone = 2;
    if (strcmp(N, "D") == 0)
        semitone = 3;
    if (strcmp(N, "D#") == 0 || strcmp(N, "Eb") == 0)
        semitone = 4;
    if (strcmp(N, "E") == 0)
        semitone = 5;
    if (strcmp(N, "F") == 0)
        semitone = 6;
    if (strcmp(N, "F#") == 0 || strcmp(N, "Gb") == 0)
        semitone = 7;
    if (strcmp(N, "G") == 0)
        semitone = 8;
    if (strcmp(N, "G#") == 0 || strcmp(N, "Ab") == 0)
        semitone = 9;
    if (strcmp(N, "A") == 0)
        semitone = 10;
    if (strcmp(N, "A#") == 0 || strcmp(N, "Bb") == 0)
        semitone = 11;
    if (strcmp(N, "B") == 0)
        semitone = 12;
    //calculate freq: semitones
    float freq = 440 * (powf(2, (semitone -10) / (float)12));
    //calculate freq: multiply by num of octaves
    return round(freq * (powf(2, octave - 4)));
}

И вывод после ./notes:

 C4: 262
C#4: 922746880
 D4: 294
helpers.c:55:12: runtime error: value 5.85908e+09 is outside the range of representable values of type 'int'
D#4: -2147483648
 E4: 330
 F4: 349
F#4: -2147483648
 G4: 392
G#4: -2147483648
 A4: 440
A#4: -2147483648
 B4: 494

Сам код работает, но он не работает в notes.c.

Пожалуйста, помогите мне понять, в чем дело.

Ответы [ 3 ]

0 голосов
/ 03 июня 2018

string - это ошибка 1 псевдоним для типа char * (указатель на char).C не имеет фактического типа данных "string";Строки представлены в виде последовательности символьных значений, за которыми следует терминатор с 0 значениями.Например, строка "hello" представлена ​​последовательностью {'h', 'e', 'l', 'l', 'o', 0}.Это завершающее значение 0 важно - без него различные библиотечные процедуры, такие как strcpy и strlen и printf, не распознают последовательность как строку.

Строки хранятся в массивах char.В большинстве случаев выражение типа "массив из char" будет преобразовано ("распад") в выражение типа "указатель на char" (char *).Таким образом, большую часть времени мы имеем дело с char * выражениями, когда имеем дело со строками.

Это, однако, не означает, что char * равно aстрока.char * может указывать на начало строки (то есть последовательность символов с нулевым символом в конце) или указывать на начало последовательности символьных значений, которая не является aстрока, или она может указывать на один символ, который не является частью большой последовательности.

С этим разглагольствованием с пути ...

, начиная с string == char *, sizeof (string) == sizeof (char *), что является числом байтов 2 в char *.NOTES - это, очевидно, массив char *, поэтому sizeof(NOTES) - это количество байтов в массиве NOTES.Разделив sizeof(NOTES) на sizeof(string), мы получим количество элементов в массиве NOTES.


Заголовочный файл cs50.h создает typedef string, я думаю, чтобы абстрагироваться от C, ну, unique семантика строк и массивов.К сожалению, это привело к большой путанице среди студентов CS50.Я лично считаю это ошибкой со стороны людей, которые создали программу CS50. Технически, «единицы хранения», но единица хранения фактически является байтом.
0 голосов
/ 14 ноября 2018

Возможно, вы захотите немного разбить это на части.

Вы получите из вашего массива:

   int octave = note[strlen(note) - 1];

, вы получите значение ASCII последней строки в виде целого числа.Чтобы преобразовать его в нужное число, вам нужно «перебрать» таблицу ASCII.

   octave -= 48; // Adjust ASCII to int value

Поскольку char 0 = ASCII 48, вы можете сделать это за один шаг.

   int octave = note[strlen(note) - 1] - '0';

Обратите внимание, что это работает, когда вы хотите вернуть целое число, представленное как альфа в вашем массиве.Если вы хотите получить обратно строку (aka char *) из вашего массива, вам нужно сделать это немного по-другому.Ключ в том, что даже длинная строка из одного символа должна заканчиваться на \ 0

Итак, теперь вы хотите получить тон:

    char N[2];
    N[0] = note[0];
    N[1] = '\0';

Обратите внимание на разницу между приведенным выше и этим:

    char N = note[0];
0 голосов
/ 03 июня 2018

Спасибо.Теперь это выглядит и работает лучше.

//parsing the string into a note...
    char N = note[0];
    //...and its octave
    int octave = note[strlen(note) - 1] - '0';
    //add semitones
    int semitone;
    if (N == 'C')
        semitone = 1;
    if (N == 'D')
        semitone = 3;
    if (N == 'E')
        semitone = 5;
    if (N == 'F')
        semitone = 6;
    if (N == 'G')
        semitone = 8;
    if (N == 'A')
        semitone = 10;
    if (N == 'B')
        semitone = 12;
    //add accidentals
    if (note[1] == '#')
        semitone ++;
    if (note[1] == 'b')
        semitone --;
    //calculate freq: semitones
    float freq = 440 * (powf(2, (semitone - 10) / (float)12));
    //calculate freq: multiply by num of octaves
    return round(freq * (powf(2, octave - 4)));

И я прочитаю больше о sizeof.

...