简体   繁体   中英

CS50 Pset3 Music - what is sizeof(string) doing?

In pset3 of CS50, we're supposed to make sense of the notes.c file:

// Prints frequencies of and outputs WAV file with all notes in an octave

#include <cs50.h>
#include <stdio.h>
#include <string.h>

#include "helpers.h"
#include "wav.h"

// Notes in an octave      
const string NOTES[] = {"C", "C#", "D", "D#", "E", "F",
                    "F#", "G", "G#", "A", "A#", "B"
                   };

// Default octave 
#define OCTAVE 4

int main(int argc, string argv[])
{
// Override default octave if specified at command line
int octave = OCTAVE;  
if (argc == 2)
{
    octave = atoi(argv[1]); 
    if (octave < 0 || octave > 8)
    {
        fprintf(stderr, "Invalid octave\n");
        return 1;
    }
}
else if (argc > 2)
{
    fprintf(stderr, "Usage: notes [OCTAVE]\n");
    return 1;
}

// Open file for writing
song s = song_open("notes.wav");

// Add each semitone
for (int i = 0, n = sizeof(NOTES) / sizeof(string); i < n; i++)
{
    // Append octave to note
    char note[4];
    sprintf(note, "%s%i", NOTES[i], octave);

    // Calculate frequency of note
    int f = frequency(note);

    // Print note to screen
    printf("%3s: %i\n", note, f);

    // Write (eighth) note to file
    note_write(s, f, 1);
}

// Close file
song_close(s);
}

The part I can't make sense of is : for (int i = 0, n = sizeof(NOTES) / sizeof(string); i < n; i++)

For sizeof(string) to work, wouldn't there need to be a variable named string somewhere in the code? eg a string actually called string ?

Not really sure what it's referring to.

sizeof can be used on variables/expressions as well as types. Here, string is a type but NOTES is an instance of a variable (an array).

The root of the problem is caused by CS-50 typedef char* string; . Overall the code is a perfect example of obfuscation. Hiding pointers behind typedefs is widely recognized as terrible practice.

What the code actually says is this:

const char* NOTES[] = { ...
...
sizeof(NOTES) / sizeof(NOTES[0])

If it had been written like above, there would be no doubt of what it does: divide the size of the array with the size of each individual member, to get the number of items in the array.

I would advise to stop using the CS-50 tutorial.

For sizeof(string) to work, wouldn't there need to be a variable named string somewhere in the code?

Nopes, sizeof operator can be used on an operand of a "type", like sizeof(int) . Quoting the spec ( emphasis mine )

The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type . [....]

You can see the usage of string type in your code:

const string NOTES[] = {"C", "C#", "D", "D#", "E", "F",
                    "F#", "G", "G#", "A", "A#", "B"
                   };

So, NOTES is an array of type string , string is a type name here.

The expression

 for (int i = 0, n = sizeof(NOTES) / sizeof(string); i < n; i++)

is a very poor attempt to count the members in the array, it could have been re-written as

 for (int i = 0, n = sizeof(NOTES) / sizeof(NOTES[0]); i < n; i++)

which basically divides the size of the whole array by the size of one element, producing the count of members, for sake of readability.

To add the exact source, Check the header file <cs50.h> , string is defined to be a type there.

The exact definition is:

 /**
 * Our own data type for string variables.
 */
typedef char *string;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM