is there a way to make this code shorter?
// Points assigned to each letter of the alphabet
int compute_score(string word);
int main(void)
{
// Get input words from both players
string word1 = get_string("Player 1: ");
string word2 = get_string("Player 2: ");
// Score both words
int score1 = compute_score(word1);
int score2 = compute_score(word2);
// TODO: Print the winner
if (score1 > score2)
{
printf("Player 1 wins!\n");
}
else if (score1 < score2)
{
printf("Player 2 wins!\n");
}
else
{
printf("Tie!\n");
}
}
the calculator function
I Haved to definition character is uppercase or lower in different loops and i think i can make that in one loop but i don't know how :)
int compute_score(string word)
{
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 len = strlen(word);
int i = 0;
int total = 0;
for (i = 0; i <= len; i++)
{
if (word[i] >= 65 && word[i] <= 90)
{
int ascii = word[i];
int toasc = ascii - 65;
total += (points[toasc]);
}
}
int ii = 0;
int totall = 0;
for (ii = 0; ii <= len; ii++)
{
if (word[ii] >= 97 && word[ii] <= 122)
{
int asciii = word[ii];
int toascc = asciii - 97;
totall += (points[toascc]);
}
}
int totalf = total + totall;
return totalf;
}
you can try something like this:
int compute_score(string word) {
int total = 0;
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 len = strlen(word);
for (i = 0; i < len; i++)
if (word[i] >= 'A' && word[i] <= 'Z')
total += points[word[i] - 'A'];
else if (word[i] >= 'a' && word[i] <= 'z')
total += points[word[i] - 'a'];
return total;
}
Normalizing the current letter to upper case which allows a fixed 'A' to be used to determine the offset into the points array. Consider changing the type of point from int to static const char [] for correctness.
#include "cs50.h"
#include <assert.h>
#include <ctype.h>
#include <stdlib.h>
#define PLAYERS 2
int compute_score(string word) {
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 total = 0;
for (; *word; word++)
total += isalpha(*word) ? points[toupper(*word) - 'A'] : 0;
return total;
}
int main(void) {
int scores[PLAYERS];
for(size_t i = 0; i < PLAYERS; i++) {
scores[i] = compute_score(get_string("Player %d: ", i + 1));
}
// TBD: generalize print of winners
static_assert(PLAYERS == 2);
if (scores[0] > scores[1]) {
printf("Player 1 wins!\n");
} else if (scores[0] < scores[1]) {
printf("Player 2 wins!\n");
} else {
printf("Tie!\n");
}
}
If you want to generalize the print of winners then it's more direct to just remember who the winners are as you go along. For example:
#include <string.h>
// ...
int main(void) {
int max_score = -1;
char winners[PLAYERS];
for(size_t i = 0; i < PLAYERS; i++) {
int score = compute_score(get_string("Player %d: ", i + 1));
if(score > max_score)
memset(winners, 0, sizeof(winners));
if(score >= max_score)
winners[i] = 1;
}
printf("Winner(s)");
for(size_t i = 0; i < PLAYERS; i++) {
if(winners[i]) printf(" %d", i + 1);
}
printf("\n");
}
You demonstrate that you know strings are arrays of characters (with a null terminator on the end).
The following uses a "purpose-built" array that stores the points of both upper and lowercase ASCII alphabet characters.
#include <stdio.h>
int compute_score( string word ) {
char tbl[] = { // small values fit into one byte
0, 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, 0, 0, 0, 0, 0,
0, 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, 0, 0, 0, 0, 0,
};
int points = 0;
for( int i = 0; word[ i ]; i++ ) { // each letter of the word
int c = word[i] - '#'; // transpose down to range 0-63
if( 0 < c && c < 4*16 ) // if still in range...
points += tbl[ c ]; // then retrieve point value of this letter
}
return points;
}
int main() { // A simple test program with a few words.
string str;
str = "Hello"; printf( "'%s' %2d pts\n", str, compute_score( str ) );
str = "world"; printf( "'%s' %2d pts\n", str, compute_score( str ) );
str = "quiz "; printf( "'%s' %2d pts\n", str, compute_score( str ) );
return 0;
}
Output
'Hello' 8 pts
'world' 9 pts
'quiz ' 22 pts
EDIT: To use an even smaller "look-up table", invoke a little "modulo arithmetic"...
int compute_score( string word ) {
// point values are arrayed correspondint to ASCII character positions
uint8_t tbl[] = {
0, 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, 0, 0, 0, 0, 0,
};
int points = 0;
for( int i = 0; word[ i ]; i++ )
if( word[ i ] >= 'A' )
points += tbl[ word[ i ] % 32 ];
return points;
}
EDIT2: Since we only want the look-up value for the upper two (alphabetic) ranges of the 7-bit ASCII table, AND C guarantees that the truth value of a condition will be either 0 (false) or 1 (true), the code could be made more contemporary using a "branchless programming" technique.
for( int i = 0; word[ i ]; i++ )
points += (word[i] >= 'A') * tbl[ word[ i ] % 32 ];
For other ASCII characters like digits or SP, the condition is false so no points are awarded. For characters in the right range, the points value is multiplied by 1 (the multiplication identity value).
Eventually, one's entire program can be reduced to a few lines... :-)
EDIT3: Now, turning attention to main() and its role in running the competition. Below combines (and renames) the function and its parameters.
The primary difference in this code is to recognise that each 'round' starts with zero. Subtracting the two players' scores
will give a positive number, zero, or a negative number.
Eliminating intermediary variables, each player gets a turn, their score computed, and the difference calculated all in one statement.
Then an appropriate message displayed.
Because this is fun, a do/while() loop offers the opportunity to play again.
#include <stdio.h>
#include "cs50.h"
int score( string word ) {
char pts = 0, tbl[] = {
0, 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, 0, 0, 0, 0, 0,
};
for( int i = 0; word[ i ]; i++ )
pts += (word[i] > 'A') * tbl[ word[ i ] % 32 ];
word[ i-1 ] = '\0'; // trim '\n' from end before printing
printf( "'%s' - %d points\n", word, pts );
return pts;
}
int main() {
do {
int diff
= score( get_string( "Player 1: " ) )
- score( get_string( "Player 2: " ) );
if( diff > 0 )
puts( "\nPlayer 1 wins!" );
else if( diff < 0 )
puts( "\nPlayer 2 wins!" );
else
puts( "\nTie!");
} while( get_int( "\nPlay again? (0-yes otherwise ending)" ) == 0 );
return 0;
}
Output
Player 1: house
'house' - 8 points
Player 2: car
'car' - 5 points
Player 1 wins!
Play again? (0-yes otherwise ending)0
Player 1:
Alternative main() using trenary "conditional operator":
int main() {
do {
int diff
= score( get_string( "Player 1: " ) )
- score( get_string( "Player 2: " ) );
puts( diff > 0 ? "\nPlayer 1 wins!" : diff < 0 ? "\nPlayer 2 wins!" : "\nTie!" );
} while( get_int( "\nPlay again? (0-yes otherwise ending)" ) == 0 );
return 0;
}
Related
#include <ctype.h>
#include <cs50.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)
{
// Get input words from both players
string word1 = get_string("Player 1: ");
string word2 = get_string("Player 2: ");
// Score both words
int score1 = compute_score(word1);
int score2 = compute_score(word2);
// TODO: Print the winner
if (score1 > score2) {
printf("The winner is Player 1!");
}
else if (score1 < score2) {
printf("The winner is Player 2!");
}
else {
printf("Both players have the same score, so it's a draw!");
}
}
int compute_score(string word)
{
int sum = 0;
for (int i = 0; i == strlen(word); i++) {
if (islower(word)) {
word = toupper(word);
}
string letter = word[i];
int first_score[i] = POINTS(letter);
for (int j = 0; j == strlen(first_score); i++) {
sum = sum + first_score[j];
}
}
}
I'm doing the second lab of the cs50 course and this gives me that error when using the islower function, why is that? supposedly the 'word' is a string, so do I have to use the ASCII numbers?
islower(int ch), toupper(int ch) expects an int. word is a pointer, thus if (islower(word)) { is a problem.
Instead code should de-reference the pointer
for (int i = 0; i == strlen(word); i++) { is weak as strlen() is called many times when only detection of a null character is needed.
tolower(word[i]) is a problem when word[i] < 0. Best to access the string as unsigned char.
POINTS(letter); fails as POINTS is an array. Care should be applied to insure the array is zero-base accessed and within range.
if not needed before calling toupper().
// Code could use a type narrower than `int` here.
unsigned char 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) {
// Access data as if unsigned char
const unsigned char *uword = (const unsigned char *) string;
int sum = 0;
while (*uword) {
if (isalpha(*uword)) {
unsigned char ch_index = toupper(*uword) - 'A';
if (ch_index < sizeof POINTS / sizeof POINTS[0]) {
sum += POINTS[ch_index];
}
}
uword++'
}
return sum;
}
Note: toupper(*uword) - 'A' only certainly works well with ASCII.
#include <ctype.h>
#include <cs50.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)
{
// Get input words from both players
string word1 = get_string("Player 1: ");
string word2 = get_string("Player 2: ");
// Score both words
int score1 = compute_score(word1);
int score2 = compute_score(word2);
if (score1 > score2)
{
printf("Player 1 Wins!\n");
}
if (score1 < score2)
{
printf("Player 2 Wins!\n");
}
else
{
printf("Tie!\n");
}
}
int compute_score(string word)
{
int score = 0;
int n = strlen(word);
for (int i = 0; i < n; i++)
{
//if letter is uppercase
if (isupper (word[i]))
{
POINTS[i] = word[i] - 65;
score += POINTS[i];
}
//if letter is lowercase
if (islower(word[i]))
{
POINTS[i] = word[i] - 97;
score += POINTS[i];
}
//if character is not a letter
else
{
i += 1;
}
}
return score;
}
//For example, when I type "Oh," for player one in command line to test; and "oh," for player two- it prints "player two wins!" (it's suppose to be a tie). When I switch, it prints bother "player 1 wins!" and "tie!" I'm at my wits end on how to solve the issue. unfortunately my debugging isn't loading properly to my computer as I was trying to practice going through and figuring it out. Any direction would be appreciated.
This is my second week trying to understand programming, I knew it'd be rough, I wasn't ready for this steep a ride!
Within the function compute_score you are changing the array POINTS
POINTS[i] = word[i] - 65;
POINTS[i] = word[i] - 97;
So it would be better if the array would be declared with the qualifier const
// Points assigned to each letter of the alphabet
const 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};
And there is no great sense to declare it as global.
Move the array declaration in the function compute_score.
Also you are incorrectly using the index i
score += POINTS[i];
And this else statement
else
{
i += 1;
}
is redundant and wrong.
The function can look the following way
int compute_score( string word )
{
// Points assigned to each letter of the alphabet
static const 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};
const size_t N = sizeof( POINTS ) / sizeof( *POINTS );
int score = 0;
for ( ; *word; ++word )
{
//if letter is uppercase
if ( isupper( ( unsigned char )*word ) )
{
size_t i = *word - 'A';
if ( i < N ) score += POINTS[i];
}
//if letter is lowercase
else if ( islower( ( unsigned char )*word ) )
{
size_t i = *word - 'a';
if ( i < N ) score += POINTS[i];
}
}
return score;
}
Also in main you have to write
if (score1 > score2)
{
printf("Player 1 Wins!\n");
}
else if (score1 < score2)
{
printf("Player 2 Wins!\n");
}
else
{
printf("Tie!\n");
}
I am attempting to solve the Codewars problem "Sum Strings as Numbers" in which you are given two strings that are numbers and you need to return a string that is the sum of these numbers. My program works for the first few tests but it breaks down when encountering random tests with strings that are hundreds of digits long. If I use the same exact input on and run the program on my own computer, there are no issues. I get this error from code wars:
Test Crashed
Caught unexpected signal: 6
and this in stderr:
free(): invalid pointer
free(): invalid pointer
this is stdout:
START
Initial variables:
llu_strlen a = 236, llu_strlen(b) = 184
llu_strlen(s1) = 236, llu_strlen(s2) = 236
ret = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
a: 78917474443946915721964827121804924300830503197284695927643616893992582376123210474159778186067315502131337563007456229418171820129259461866211403468685049537996202816061990624398601182936240354459414060583378547091248670096407399362798
s1: 78917474443946915721964827121804924300830503197284695927643616893992582376123210474159778186067315502131337563007456229418171820129259461866211403468685049537996202816061990624398601182936240354459414060583378547091248670096407399362798
b: 2750702483149509093439330294177302822318268374477554716003096683744873506434616984296831843933180888658289619326781012055684240461466622908813033352854623703899221940600376950489726654
s2: 00000000000000000000000000000000000000000000000000002750702483149509093439330294177302822318268374477554716003096683744873506434616984296831843933180888658289619326781012055684240461466622908813033352854623703899221940600376950489726654
entering sum loop:
i = 0, digita = 8, digitb = 4, sumstr=12
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002
i = 1, digita = 9, digitb = 5, sumstr=15
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000052
i = 2, digita = 7, digitb = 6, sumstr=14
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000452
i = 3, digita = 2, digitb = 6, sumstr=09
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009452
i = 4, digita = 6, digitb = 2, sumstr=08
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000089452
i = 5, digita = 3, digitb = 7, sumstr=10
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000089452
i = 6, digita = 9, digitb = 9, sumstr=19
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009089452
i = 7, digita = 9, digitb = 8, sumstr=18
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000089089452
i = 8, digita = 3, digitb = 4, sumstr=08
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000889089452
i = 9, digita = 7, digitb = 0, sumstr=07
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007889089452
i = 10, digita = 0, digitb = 5, sumstr=05
(continues on like that for a while)
000000000000000000000000000121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 210, digita = 7, digitb = 0, sumstr=07
000000000000000000000000007121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 211, digita = 2, digitb = 0, sumstr=02
000000000000000000000000027121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 212, digita = 8, digitb = 0, sumstr=08
000000000000000000000000827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 213, digita = 4, digitb = 0, sumstr=04
000000000000000000000004827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 214, digita = 6, digitb = 0, sumstr=06
000000000000000000000064827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 215, digita = 9, digitb = 0, sumstr=09
000000000000000000000964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 216, digita = 1, digitb = 0, sumstr=01
000000000000000000001964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 217, digita = 2, digitb = 0, sumstr=02
000000000000000000021964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 218, digita = 7, digitb = 0, sumstr=07
000000000000000000721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 219, digita = 5, digitb = 0, sumstr=05
000000000000000005721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 220, digita = 1, digitb = 0, sumstr=01
000000000000000015721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 221, digita = 9, digitb = 0, sumstr=09
000000000000000915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 222, digita = 6, digitb = 0, sumstr=06
000000000000006915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 223, digita = 4, digitb = 0, sumstr=04
000000000000046915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 224, digita = 9, digitb = 0, sumstr=09
000000000000946915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 225, digita = 3, digitb = 0, sumstr=03
000000000003946915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 226, digita = 4, digitb = 0, sumstr=04
000000000043946915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 227, digita = 4, digitb = 0, sumstr=04
000000000443946915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 228, digita = 4, digitb = 0, sumstr=04
000000004443946915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 229, digita
here is the program that I run on code wars which throws an error:
#include <malloc.h>
#include <string.h>
unsigned long long llu_strlen(const char * s)
{
unsigned long long len = 0;
while (s[len])
len++;
return len;
}
char *strsum(const char *a, const char *b)
{
puts("START");
static char * ret;
char sumstr[] = "00";
char digita, digitb;
unsigned long long maxlen, i, carry;
if (llu_strlen(a) == 0 || llu_strlen(b) == 0)
return NULL;
maxlen = llu_strlen(a) > llu_strlen(b) ? llu_strlen(a) : llu_strlen(b);
// create ret full of maxlen+1 0s plus a '\0'. total size is maxlen+2
ret = (char *) malloc((maxlen+2) * sizeof(char));
for (i = 0; i < maxlen+1; i++)
ret[i] = '0';
ret[maxlen+1] = '\0';
// create copies of a and b of equal size by buffering with 0s
char s1[maxlen], s2[maxlen];
for (i = 0; i < maxlen - llu_strlen(a); i++)
s1[i] = '0';
strcpy(s1+i, a);
for (i = 0; i < maxlen - llu_strlen(b); i++)
s2[i] = '0';
strcpy(s2+i, b);
puts("Initial variables:");
printf("llu_strlen a = %llu, llu_strlen(b) = %llu\n", llu_strlen(a), llu_strlen(b));
printf("llu_strlen(s1) = %llu, llu_strlen(s2) = %llu\n", llu_strlen(s1), llu_strlen(s2));
printf("ret = %s\n", ret);
printf("a: %s\n", a);
printf("s1: %s\n", s1);
printf("b: %s\n", b);
printf("s2: %s\n", s2);
// sum loop
printf("entering sum loop:\n");
for (i = carry = 0; i < maxlen; i++)
{
digita = s1[maxlen-1-i] - 48;
digitb = s2[maxlen-1-i] - 48;
sprintf(sumstr, "%02llu", digita + digitb + carry);
carry = sumstr[0] - 48;
ret[maxlen-i] = sumstr[1];
printf("i = %llu, digita = %d, digitb = %d, sumstr=%s\n", i, digita, digitb, sumstr);
puts(ret);
}
printf("Done with that\n");
ret[0] = carry + 48;
// remove preceeding zeros
while (*ret == '0' && *(ret+1) != '\0')
ret++;
printf("final ret: %s\nEND\n\n", ret);
return ret;
}
and here is the program I run on my computer which finds the result successfully:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
unsigned long long llu_strlen(const char * s)
{
unsigned long long len = 0;
while (s[len])
len++;
return len;
}
char *strsum(const char *a, const char *b)
{
puts("START");
static char * ret;
char sumstr[] = "00";
char digita, digitb;
unsigned long long maxlen, i, carry;
if (llu_strlen(a) == 0 || llu_strlen(b) == 0)
return NULL;
maxlen = llu_strlen(a) > llu_strlen(b) ? llu_strlen(a) : llu_strlen(b);
// create ret full of maxlen+1 0s plus a '\0'. total size is maxlen+2
ret = (char *) malloc((maxlen+2) * sizeof(char));
for (i = 0; i < maxlen+1; i++)
ret[i] = '0';
ret[maxlen+1] = '\0';
// create copies of a and b of equal size by buffering with 0s
char s1[maxlen], s2[maxlen];
for (i = 0; i < maxlen - llu_strlen(a); i++)
s1[i] = '0';
strcpy(s1+i, a);
for (i = 0; i < maxlen - llu_strlen(b); i++)
s2[i] = '0';
strcpy(s2+i, b);
puts("Initial variables:");
printf("llu_strlen a = %llu, llu_strlen(b) = %llu\n", llu_strlen(a), llu_strlen(b));
printf("llu_strlen(s1) = %llu, llu_strlen(s2) = %llu\n", llu_strlen(s1), llu_strlen(s2));
printf("ret = %s\n", ret);
printf("a: %s\n", a);
printf("s1: %s\n", s1);
printf("b: %s\n", b);
printf("s2: %s\n", s2);
// sum loop
printf("entering sum loop:\n");
for (i = carry = 0; i < maxlen; i++)
{
digita = s1[maxlen-1-i] - 48;
digitb = s2[maxlen-1-i] - 48;
sprintf(sumstr, "%02llu", digita + digitb + carry);
carry = sumstr[0] - 48;
ret[maxlen-i] = sumstr[1];
printf("i = %llu, digita = %d, digitb = %d, sumstr=%s\n", i, digita, digitb, sumstr);
puts(ret);
}
printf("Done with that\n");
ret[0] = carry + 48;
// remove preceeding zeros
while (*ret == '0' && *(ret+1) != '\0')
ret++;
printf("final ret: %s\nEND\n\n", ret);
return ret;
}
int main(void)
{
char * res;
res = strsum("78917474443946915721964827121804924300830503197284695927643616893992582376123210474159778186067315502131337563007456229418171820129259461866211403468685049537996202816061990624398601182936240354459414060583378547091248670096407399362798",
"2750702483149509093439330294177302822318268374477554716003096683744873506434616984296831843933180888658289619326781012055684240461466622908813033352854623703899221940600376950489726654");
return 0;
}
The error always occurs while the print statement in the sum for loop is printing. The amount of stuff that print statement manages to print out before being cut off changes every time the program is run. This test has random strings of numbers as input, so the input changes each time. The error usually occurs when i approaches maxlen, but i can sometimes be 30-40 less than maxlen.
In your function you allocate ret in this line:
ret = (char *) malloc((maxlen+2) * sizeof(char));
you then return ret at the end of your function, presumably to be freed by the caller.
However within your function you also have these lines:
// remove preceeding zeros
while (*ret == '0' && *(ret+1) != '\0')
ret++;
This means that the the ret you are returning no longer has the same pointer value as the one you received from malloc. Then when you call free in the caller the free function doesn't know what the pointer is.
One way to fix this is to find a different way to remove leading zeros, one that doesn't change the value of ret.
These don't have room for the null terminator:
char s1[maxlen], s2[maxlen];
which makes your program write out of bounds and have undefined behavior, so make them:
char s1[maxlen+1], s2[maxlen+1];
And here you change ret, making it impossible for a user to free the malloced memory:
while (*ret == '0' && *(ret+1) != '\0')
ret++;
instead, move the part of the string that you want to keep:
char *tmp = ret;
while (*tmp == '0' && tmp[1] != '\0') tmp++;
memmove(ret, tmp, maxlen-(tmp-ret)+2);
Another detail: You declare ret as static which only makes it unsafe to use the function in a multithreaded program. It does not provide any benefits at all. Just make it:
char *ret;
Another possible improvement would be to not allocate s1 and s2 at all, but to read directly from a and b and to skip leading zeroes before doing the calculation. Example:
#define SWAP(type, x, y) \
do { \
type tmp = x; \
x = y; \
y = tmp; \
} while (0)
char *strsum(const char *a, const char *b) {
while(*a == '0' && a[1] != '\0') ++a; // skip leading zeroes
while(*b == '0' && b[1] != '\0') ++b; // skip leading zeroes
size_t lena = strlen(a);
size_t lenb = strlen(b);
if (lena == 0 || lenb == 0) return NULL;
if (lena < lenb) { // make `a` the longest string
SWAP(const char *, a, b);
SWAP(size_t, lena, lenb);
}
char *ret = malloc(lena + 2); // may add one digit + null terminator
ret[lena + 1] = '\0'; // null terminate the result
int carry = 0;
size_t i = 1;
// loop while both `b` and `a` have digits:
for (; i <= lenb; ++i) {
int sum = carry + (a[lena - i] - '0') + (b[lenb - i] - '0');
ret[lena - i + 1] = (sum % 10) + '0';
carry = sum / 10;
}
// loop while only `a` has digits:
for (; i <= lena; ++i) {
int sum = carry + (a[lena - i] - '0');
ret[lena - i + 1] = (sum % 10) + '0';
carry = sum / 10;
}
// if no carry, move everything one step to the left:
if (carry == 0) memmove(ret, ret + 1, lena + 2 - 1);
else ret[0] = carry + '0'; // carry goes to the first position
return ret;
}
Demo
I'm quite new to programming and I am in the middle of doing CS50, and in this scrabble program I'm having trouble because I can't figure out which segmentation error I am making. It may be that my index is outside my array. If you could find the problem and also explain it to me I would be grateful.
#include <ctype.h>
#include <cs50.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)
{
// Get input words from both players
string word1 = get_string("Player 1: ");
string word2 = get_string("Player 2: ");
// Score both words
int score1 = compute_score(word1);
int score2 = compute_score(word2);
if (score1 > score2)
{
printf("Player 1 wins!\n");
}
else if (score1 == score2)
{
printf("Tie!\n");
}
else
{
printf("Player 2 wins!\n");
}
// TODO: Print the winner
}
int compute_score(string word)
{
int number;
int sum1=0;
for (int i = 0; i<strlen(word); i++)
{
if (isupper(word))
{
number = POINTS[word[i]-'A'];
}
else if (word[i] < 97 || word[i]>122 || word[i]<65 || word[i]>90)
{
number = 0;
}
else
{
number = POINTS[word[i] - 'a'];
}
sum1 = sum1 + number;
}
return sum1;
// Assign points to letters
// read the letters in the word
// covert the letters into scores and add
// TODO: Compute and return score for string
}
At least this condition in the if statement
if (isupper(word))
is incorrect. You have to write
if (isupper( ( unsigned char )word[i]))
The condition in this if statement
else if (word[i] < 97 || word[i]>122 || word[i]<65 || word[i]>90)
does not make a sense. For starters do not use magic numbers like for example 97. The condition can look like
else if ( !( ( word[i] >= 'a' && word[i] <= 'z' ) || ( word[i] >= 'A' && word[i] <= 'Z' ) ) )
I'm trying to implement the Vigenere Cipher, but I have a problem while trying to loop trough the key. First, all the little functions, although, I don't think the problem is there.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#define ALPHANUMERIC "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" /* all alphabetic characters at their corresponding indices */
char* squeeze(char[], int);
char* formatString(char[]);
int findindex(char c);
/* squeeze: remove all occurences of c in s */
char* squeeze(char s[], int c)
{
int i, j;
for (i = j = 0; s[i] != '\0'; i++)
if (s[i] != c)
s[j++] = s[i];
s[j] = '\0';
// printf("%s\n", s);
return s;
}
/* formatString: remove all white spaces and special
characters and convert all letters to upper case */
char* formatString(char input[])
{
int i;
input = squeeze(input, ' ');
for (i = 0; input[i] != '\0'; i++)
{
if (!isalnum(input[i]))
{
input = squeeze(input, input[i]);
--i;
}
if (islower(input[i]))
input[i] = toupper(input[i]);
}
// printf("%s\n", input);
return input;
}
/* findindex: returns the predefined index of a given character */
int findindex(char c)
{
int i;
if (isdigit(c))
return 26 + c - '0';
for (i = 0; ALPHANUMERIC[i] != '\0'; i++)
if (c == ALPHANUMERIC[i])
return i;
return -1;
}
And here is the cipher-function. Just to clarify, my idea was to loop through the text-string in the for-loop and use the j-counter to loop through the codeword by setting it to zero, when it reaches the end of the codeword. All the extra printf-s are for debugging purposes.
void cipher(char codeword[], char text[])
{
int i, j;
char newword[strlen(text)];
codeword = formatString(codeword);
text = formatString(text);
printf("codeword = %s, text = %s\n", codeword, text );
j = -1;
for (i = 0; i < strlen(text); i++)
{
j++;
printf("text[i] = %c, %d, codeword = %c, %d\n", text[i], findindex(text[i]), codeword[i], findindex(codeword[i]));
newword[i] = ALPHANUMERIC[(findindex(text[i]) + findindex(codeword[j])) % 36];
printf("i = %d, j = %d\n", i, j);
if (j == strlen(codeword) - 1)
j = -1;
}
printf("%s\n", newword);
}
So, looking at the code, it all seems fine, until i run it. That's the output with input "ivcho", "ivayloivayloo":
codeword = IVCHO, text = IVAYLOIVAYLOO
text[i] = I, 8, codeword = I, 8
i = 0, j = 0
text[i] = V, 21, codeword = V, 21
i = 1, j = 1
text[i] = A, 0, codeword = C, 2
i = 2, j = 2
text[i] = Y, 24, codeword = H, 7
i = 3, j = 3
text[i] = L, 11, codeword = O, 14
i = 4, j = 4
text[i] = O, 14, codeword = , -1
i = 5, j = 0
text[i] = I, 8, codeword = , -1
i = 6, j = 1
text[i] = V, 21, codeword = , -1
i = 7, j = 2
text[i] = A, 0, codeword = , -1
i = 8, j = 3
text[i] = Y, 24, codeword = G, 6
i = 9, j = 4
text[i] = L, 11, codeword = C, 2
i = 10, j = 0
text[i] = O, 14, codeword = C, 2
i = 11, j = 1
text[i] = O, 14, codeword = :, -1
i = 12, j = 2
QGC5ZW3XHCT9Q
When the counter (j) is set to zero, it just doesn't start over and I have no idea why.