Week 2 Arrays¶
约 857 个字 322 行代码 预计阅读时间 7 分钟
Syllabus¶
Preprocessing. Compiling. Assembling. Linking. Debugging. Arrays. Strings. Command-Line Arguments. Cryptography.
Notes¶
Preprocessing¶
Motivation: reading levels
Recall a graph:
Source Code -> Compiler -> Machine Code
Compiling¶
What's actually happend in the process of translating?(Compiling)
preprocessor preprocessing step
If you want to code C or other languages, the CPU will process the code from C into a low levlel language called assembly code.
And focus on compiling
What's the definition of linking neatly?
A: the process of combining multiple object files (pieces of compiled code) generated by a compiler into a single executable program.
Four steps of compiling:
+ preprocessing
+ compile to assembly code
+ assembly code translates to machine code
+ linking: combining multiple object files (pieces of compiled code)
Debugging¶
- Everyone will make mistakes while coding.
- Debugging is the process of locating and removing bugs from your code.
#include <stdio.h>
int main(void)
{
for (int i = 0; i < 3; i++)
{
printf("i is %i\n", i);
printf("#\n");
}
}
Arrays¶
Motivation: We don't want so many variables for a same type(or same purpose)
So this tech has an advantage that we can change it easily and sustained.
// Averages three numbers using an array, a constant, and a helper function
#include <cs50.h>
#include <stdio.h>
// Constant
const int N = 3;
// Prototype
float average(int length, int array[]);
int main(void)
{
// Get scores
int scores[N];
for (int i = 0; i < N; i++)
{
scores[i] = get_int("Score: ");
}
// Print average
printf("Average: %f\n", average(N, scores));
}
float average(int length, int array[])
{
// Calculate average
int sum = 0;
for (int i = 0; i < length; i++)
{
sum += array[i];
}
return sum / (float) length;
}
Strings¶
- A
string
is simply an array of variables of typechar
: an array of characters. - To explore
char
andstring
, typecode hi.c
in the terminal window and write code as follows:
// Prints chars
#include <stdio.h>
int main(void)
{
char c1 = 'H';
char c2 = 'I';
char c3 = '!';
printf("%c%c%c\n", c1, c2, c3);
}
Notice that this will output a string of characters.
A string is a sequence of characters like a array of the type of characters.
NUL says string end here.
#include <cs50.h>
#include <stdio.h>
int main(void)
{
string words[2];
words[0] = "HI!";
words[1] = "BYE!";
printf("%c%c%c\n", words[0][0], words[0][1], words[0][2]);
printf("%c%c%c%c\n", words[1][0], words[1][1], words[1][2], words[1][3]);
// arrays of arrays so strings are actually arrays
}
strlen function include
Since this is such a common problem within programming, other programmers have created code in the string.h
library to find the length of a string. You can find the length of a string by modifying your code as follows:
// Determines the length of a string using a function
#include <cs50.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
// Prompt for user's name
string name = get_string("Name: ");
int length = strlen(name);
printf("%i\n", length);
}
Notice that this code uses the string.h
library, declared at the top of the file. Further, it uses a function from that library called strlen
, which calculates the length of the string passed to it.
ctype.h
While the program does what we want, there is an easier way using the ctype.h
library. Modify your program as follows:
// Uppercases string using ctype library (and an unnecessary condition)
#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
string s = get_string("Before: ");
printf("After: ");
for (int i = 0, n = strlen(s); i < n; i++)
{
if (islower(s[i]))
{
printf("%c", toupper(s[i]));
}
else
{
printf("%c", s[i]);
}
}
printf("\n");
}
Notice that the program iterates through each character of the string. The toupper
function is passed s[i]
. Each character (if lowercase) is converted to uppercase.
Command-Line Arguments¶
Command-line arguments
are those arguments that are passed to your program at the command line. For example, all those statements you typed afterclang
are considered command line arguments. You can use these arguments in your own programs!-
In your terminal window, type
code greet.c
and write code as follows:
Notice that this says hello
to the user.
-
Still, would it not be nice to be able to take arguments before the program even runs? Modify your code as follows:
Notice that this program knows both argc
, the number of command line arguments, and argv
, which is an array of the characters passed as arguments at the command line.
Remark that one of CLAs is the name of the program!
- Therefore, using the syntax of this program, executing
./greet David
would result in the program sayinghello, David
. - You can print each of the command-line arguments with the following:
// Prints command-line arguments
#include <cs50.h>
#include <stdio.h>
int main(int argc, string argv[])
{
for (int i = 0; i < argc; i++)
{
printf("%s\n", argv[i]);
}
}
Exit Status¶
- When a program ends, a special exit code is provided to the computer.
- When a program exits without error, a status code of
0
is provided to the computer. Often, when an error occurs that results in the program ending, a status of1
is provided by the computer. -
You could write a program as follows that illustrates this by typing
code status.c
and writing code as follows:
Notice that if you fail to provide ./status David
, you will get an exit status of 1
. However, if you do provide ./status David
, you will get an exit status of 0
.
- You can type
echo $?
in the terminal to see the exit status of the last run command. - You can imagine how you might use portions of the above program to check if a user provided the correct number of command-line arguments.
Cryptography¶
- Cryptography is the art of ciphering and deciphering a message.
- Now, with the building block of arrays, chars, and strings, you can cipher and decipher a message.
plaintext
and akey
are provided to acipher
, resulting in ciphered text.
Key and Plaintext -> Cipher -> Ciphertext
Summing Up¶
In this lesson, you learned more details about compiling and how data is stored within a computer. Specifically, you learned…
- Generally, how a compiler works.
- How to debug your code using four methods.
- How to utilize arrays within your code.
- How arrays store data in back to back portions of memory.
- How strings are simply arrays of characters.
- How to interact with arrays in your code.
- How command-line arguments can be passed to your programs.
- The basic building-blocks of cryptography.
Sections¶
- Arrays
- Initialize
- assignment
- change
- Strings
- get_string
- Connection with arrays
- ASCII code(Alphabetical Exercise)
- Command Line Arguments aka. CLA
A program about CLAs:
#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
int main(int argc, string argv[])
{
// Get user's input
if (argc != 2)
{
printf("Please provide a word.\n");
return 1;
}
string text = argv[1];
int len = strlen(text);
for (int i = 0; i < len; i++)
{
if (!isalpha(text[i]))
{
printf("This is not a letter.\n");
return 2;
}
}
// Iterate through each element in the string
for (int i = 1; i < len; i++)
{
if (text[i] < text[i - 1])
{
printf("No\n");
return 0;
}
}
// Print out yes
printf("Yes\n");
}
Problem Set 2¶
Scrabble¶
#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
// Points assigned to each letter of the alphabet
int POINTS[] = {1, 3, 3, 2, 1, 4, 2, 4, 1, 8, 5, 1, 3, 1, 1, 3, 10, 1, 1, 1, 1, 4, 4, 8, 4, 10};
int compute_score(string word);
int main(void)
{
// Prompt the user for two words
string word1 = get_string("Player 1: ");
string word2 = get_string("Player 2: ");
// Compute the score of each word
int score1 = compute_score(word1);
int score2 = compute_score(word2);
// Print the winner
if (score1 > score2)
{
printf("Player 1 wins!\n");
}
else if (score1 < score2)
{
printf("Player 2 wins!\n");
}
else
{
printf("Tie!\n");
}
}
int compute_score(string word)
{
// Keep track of score
int score = 0;
// Compute score for each character
for (int i = 0, len = strlen(word); i < len; i++)
{
if (isupper(word[i]))
{
score += POINTS[word[i] - 'A'];
}
else if (islower(word[i]))
{
score += POINTS[word[i] - 'a'];
}
}
return score;
}
Readability¶
#include <ctype.h>
#include <cs50.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
int count_letters(string text);
int count_words(string text);
int count_sentences(string text);
int main(void)
{
// Prompt the user for some text
string text = get_string("Text: ");
// Count the number of letters, words, and sentences in the text
int letters = count_letters(text);
int words = count_words(text);
int sentences = count_sentences(text);
// Compute the Coleman-Liau index
float L = (float)letters / words * 100; // Average letters per 100 words
float S = (float)sentences / words * 100; // Average sentences per 100 words
float index_original = 0.0588 * L - 0.296 * S - 15.8; // Coleman-Liau index formula
// Print the grade level
int index = round(index_original);
if (index < 1)
{
printf("Before Grade 1\n");
}
else if (index >= 16)
{
printf("Grade 16+\n");
}
else
{
printf("Grade %d\n", index);
}
}
int count_letters(string text)
{
// Return the number of letters in text
int letter_count = 0;
for (int i = 0, n = strlen(text); i < n; i++)
{
if (isalpha(text[i]))
{
letter_count++;
}
}
return letter_count; // Return the count of letters
}
int count_words(string text)
{
// Return the number of words in text
int word_count = 0;
for (int i = 0, n = strlen(text); i < n; i++)
{
if (isspace(text[i]) || i == n - 1) // Count words by spaces or end of text
{
word_count++;
}
}
return word_count; // Return the count of words
}
int count_sentences(string text)
{
// Return the number of sentences in text
int sentence_count = 0;
for (int i = 0, n = strlen(text); i < n; i++)
{
if (text[i] == '.' || text[i] == '!' || text[i] == '?')
{
sentence_count++;
}
}
return sentence_count; // Return the count of sentences
}
Caesar¶
#include <cs50.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, string argv[])
{
// Make sure program was run with just one command-line argument
if (argc != 2)
{
printf("Usage: ./caesar key\n");
return 1;
}
// Make sure every character in argv[1] is a digit
for (int i = 0, n = strlen(argv[1]); i < n; i++)
{
if (argv[1][i] < '0' || argv[1][i] > '9')
{
printf("Usage: ./caesar key\n");
return 1;
}
}
// Convert argv[1] from a `string` to an `int`
int key = atoi(argv[1]) % 26; // Ensure key is within 0-25
// Prompt user for plaintext
string plaintext = get_string("plaintext: ");
// For each character in the plaintext:
printf("ciphertext: ");
for (int i = 0, n = strlen(plaintext); i < n; i++)
{
// Check if the character is an uppercase letter
if (plaintext[i] >= 'A' && plaintext[i] <= 'Z')
{
// Rotate the character
printf("%c", ((plaintext[i] - 'A' + key) % 26) + 'A');
}
// Check if the character is a lowercase letter
else if (plaintext[i] >= 'a' && plaintext[i] <= 'z')
{
// Rotate the character
printf("%c", ((plaintext[i] - 'a' + key) % 26) + 'a');
}
else
{
// If it's not a letter, just print it as is
printf("%c", plaintext[i]);
}
}
printf("\n");
return 0;
}
Substitution¶
#include <cs50.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main(int argc, string argv[])
{
// Make sure program was run with just one command-line argument
if (argc != 2)
{
printf("Usage: ./substitution key\n");
return 1;
}
// Optimize: Calculate key length once
int key_len = strlen(argv[1]);
for (int i = 0; i < key_len; i++)
{
// Check if the key contains only alphabetic characters
if (!isalpha(argv[1][i]))
{
printf("Key must contain 26 characters.\n");
return 1;
}
}
// Make sure argv[1] has 26 characters (Logic preserved as per original code)
for (int i = 0; i < key_len; i++) // Use pre-calculated key_len
{
if ((argv[1][i] <= 'z' && argv[1][i] >= 'a') || (argv[1][i] <= 'Z' && argv[1][i] >= 'A'))
{
// Use pre-calculated key_len here as well
if (key_len != 26) // Use pre-calculated key_len
{
printf("Key must contain 26 characters.\n");
return 1;
}
else
{ // Check for duplicate characters in the key
for (int j = 0; j < key_len; j++) // Use pre-calculated key_len
{
for (int k = j + 1; k < key_len; k++) // Use pre-calculated key_len
{
if (argv[1][j] == argv[1][k] || argv[1][j] + 32 == argv[1][k] || argv[1][j] - 32 == argv[1][k])
{
printf("Key must not contain repeated characters.\n");
return 1;
}
}
}
// Prompt user for plaintext
string plaintext = get_string("plaintext: ");
// Optimize: Calculate plaintext length once
int plaintext_len = strlen(plaintext);
// For each character in the plaintext:
for (int j = 0; j < plaintext_len; j++) // Use pre-calculated plaintext_len
{
if ((plaintext[j] - 'a') >= 0 && (plaintext[j] - 'a') <= 26) // Original condition preserved
{
// Convert lowercase letters
plaintext[j] = argv[1][plaintext[j] - 'a'];
if (plaintext[j] >= 'A' && plaintext[j] <= 'Z')
{
// Convert to lowercase if necessary
plaintext[j] += 32; // ASCII value adjustment
}
}
else if ((plaintext[j] - 'A') >= 0 && (plaintext[j] - 'A') <= 26) // Original condition preserved
{
// Convert uppercase letters
plaintext[j] = argv[1][plaintext[j] - 'A'];
if (plaintext[j] >= 'a' && plaintext[j] <= 'z')
{
// Convert to uppercase if necessary
plaintext[j] -= 32; // ASCII value adjustment
}
}
}
printf("ciphertext: %s\n", plaintext);
return 0;
}
}
else
{
printf("Usage: ./substitution key\n");
return 1;
}
}
// Note: The original code's control flow causes it to exit the main function within the first iteration
// of the key validation loop (if conditions are met).
// This final 'return 0' would only be reached if the key_len was 0 or the loop somehow finished without returning.
return 0;
}