Problems with sums of chars in C - c

I'm very new to C so I'll make it quick: I'm making a Caesar's Cipher but at some point it starts giving me ? symbols.
#include <stdio.h>
#include <ctype.h>
int main(void){
char c;
int k;
printf("Inserisci la chiave di cifratura: ");
scanf("%d", &k);
if (k > 26)
k = (k%26);
printf("%d", k);
while ((c=getchar()) != '.') {
if (isalpha(c)) {
if (c >= 'a' && c <= 'z') {
c = c + k;
if (c > 'z') {
c = c - 'z' + 'a' - 1;
}
}
else if (c >= 'A' && c <= 'Z') {
c = c + k;
if (c > 'Z') {
c = c - 'Z' + 'A' - 1;
}
}
putchar(c);
}
else
putchar(c);
}
printf("\n");
return 0;
}
If k is 6, it starts giving me the symbol with z.
If it is 7, it start with y.
Etc...
I can't find anything around, thank you to whoever helps me.

When you use char, it's implementation-defined whether it's treated as signed char or unsigned char. Your implementation apparently defaults to signed char. The value of 'z' is 122, and when you add 6 to this you get 128, which overflows and causes undefined behavior. The maximum value of signed char is 127.
You should declare c to be int or unsigned char.

Your solution ensures the offset k is in the range of 0 through 26. You can get the correct solution if your offset is in the range of 0 through 25. An offset of 26 should produce the same results as an offset of 0.
When calculating the offset character you simply add K and then try to use addition to adjust for values greater than 'z' or 'Z'. You can adjust the value without the use of another set of conditional statements using the modulus operator.
Since this appears to be a homework problem I have created a solution in Ada rather than C. You can translate the logic into C.
with Ada.Text_Io; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
procedure Main is
subtype Offset is Natural range 0..25;
K : Offset;
C : Character := ' ';
Code : Natural;
adjusted : Character;
begin
Put("Enter the letter shift amount: ");
Get(K);
Put_Line("Specified offset is" & K'Image);
while C /= '.' loop
Get(C);
if C in 'a'..'z' then
Code := (Character'Pos(C) - Character'Pos('a') + k) mod 26;
adjusted := Character'Val(Code + Character'Pos('a'));
Put(adjusted);
elsif C in 'A'..'Z' then
Code := (Character'Pos(C) - Character'Pos('A') + k) mod 26;
adjusted := Character'Val(Code + Character'Pos('A'));
Put(adjusted);
else
Put(C);
end if;
end loop;
end Main;
Ada does not allow arithmetic directly on characters. Instead it allows arithmetic on the "position" of the character, which is a numeric value. The function Character'Pos(C) returns the numeric position of the character stored in variable C. The function Character'Val() returns the character corresponding to a specified numeric value.

Related

How to calculate the frequency of a character in a string in C

I have found code that calculate the frequency of a character in a string, however, all of them are using the same line of code and don't explain what it means. Can someone please enlighten me?
Here is an example:
int c = 0, count[26] = {0}, x;
while (string[c] != '\0') {
/** Considering characters from 'a' to 'z' only and ignoring others. */
if (string[c] >= 'a' && string[c] <= 'z') {
x = string[c] - 'a';
count[x]++;
}
I understand that the loop will iterate through the string until it reaches the end.
I also get the if statement, as that only limits it between a and z.
However, I have no idea what x = string[c] -'a' is doing, why is it subtracting 'a'?
I also don't understand what the purpose of count[26] is.
Here is where I got this program from:
https://www.programmingsimplified.com/c-program-find-characters-frequency
Any help would be great thanks.
TL;DR Is taken advantage of the ASCII table.
The code only accepts characters from a to z:
if (string[c] >= 'a' && string[c] <= 'z')
therefore it creates an array with 26 positions (i.e., count[26]) to store the frequency of those same characters. The following
x = string[c] - 'a';
converts string[c] into an int; fact which can be used to take advantage of the ASCII table.
According to the ASCII table the letters 'a' to 'z' are represented by the int values from 97 to 112, respectively. Therefore, because arrays in C start with 0 we need to shift 97 elements to the left from the value that will be return by string[c], namely:
x = string[c] - 97;
which can be represented by
x = string[c] - 'a';
With this trick if string[c] is 'a' then :
x = 'a' - 'a';
which is converted to x = 97 - 97, then x = 0; Therefore,
count[x]++; is count[0]++;
which increments by 1 the position 0 of the array count, which is "reserved" to the letter 'a'. This same logic applies to all the other letters from 'a' to 'z'.
Bear in mind, however, and quoting Eric Postpischil:
The character codes used in C implementations do not necessarily have
all the letters consecutively. ASCII does and is very common, but not
required by the standard.
Hence, this solution will work if your encoding is ASCII.
count[26] is the frequency table. count[0] is the number of occurrences of a. count[1] is the number of occurrences of b, etc...
Initialize the count array to all zero values
count[26] = {0}
While not at the end of the string. Remember, C strings always end with a null char (\0).
while (string[c] != '\0') {
Evaluate if the character at string[c] is between a and z
if (string[c] >= 'a' && string[c] <= 'z') {
Normalize the ascii value of this character (which will be between 97 and 122) to a value from 0 to 25. a is 97 when evaluated in a math expression.
x = string[c] - 'a';
Using the x value computed above, use that as an index into the count table
Increment whatever value that is in count[x] by 1.
count[x]++;
What's missing from this code sample is the place where c gets incremented by 1 such that string[c] is referencing the next character in the string.
In the ASCII data base, 'a' to 'z' have consecutive numerical code from 0x61 to 0x7A. cf. man ascii.
Hence, if you substract the value of 'a', you get numbers from 0 to 25. This number is an index in count[] table.
count[26] is an array of 26 integers, each one represent the count of a lowercase letter from 'a' to 'z' from within string
count[0] is the counter for 'a', count[1] is the counter for 'b' etc...
x = string[c] - 'a' calculates and assign to x the index 0-25 for the char found at string[c].
Simplifyng: remember that 'a' is the integer ascii value 97 decimal. The subtraction of 'a' is to reduce all indexes from 'a' to 'z' to a value from 0 to 25 needed for the count[] array.
First, that code depends on the characters 'a' through 'z' being represented consecutively, something that's common but not guaranteed.
Second,
int c = 0, count[26] = {0}, x;
while (string[c] != '\0') {
/** Considering characters from 'a' to 'z' only and ignoring others. */
if (string[c] >= 'a' && string[c] <= 'z') {
x = string[c] - 'a';
count[x]++;
}
has several issues and I'd say is more clear as
#include <ctype.h>
// multiple variables on one line is ***very*** bug prone
// so don't do it
int c = 0;
int count[26] = {0};
// set the input - unsigned is important
unsigned char *string = ...;
// loop until the character pointed at by string is '\0'
while ( *string )
{
// islower() returns non-zero only if the unsigned char value
// passed is a lower-case letter.
//
// If the input int value can't be represented as an unsigned
// char the results are undefined behavior (because tolower()
// actually takes an int argument.)
//
// signed char will be sign-extended when passed as an int argument
if ( islower( *string ) )
{
// get the "index" of the lower-case letter
// a -> 0, b -> 1, z -> 25
// depends on a-z being consecutive - not necessarily true
int x = *string - 'a';
// increment the number of times this lower-case character
// is in this string
count[x]++;
}
// go to the next character in the string
string++;
}
Note that there is zero effort on my part to reduce the number of lines used. You gain nothing by cramming code into fewer lines, but you will make the code harder to read and therefore more bug prone.
A better way to count characters in a string:
#include <limits.h>
void countChars( unsigned char *string )
{
int counts[ UCHAR_MAX ] = { 0 };
while ( *string )
{
counts[ *string ]++;
string++;
}
}
If you want to count lower-case characters:
#include <limits.h>
void countLowerCaseChars( unsigned char *string )
{
int counts[ UCHAR_MAX ] = { 0 };
while ( *string )
{
counts[ tolower( *string ) ]++;
string++;
}
}

Can we set a variable to a number range in C?

What I'm thinking of is something like this:
range = range <= '9' && range >= '0';
I want to extract a contiguous sequence of digits from a string. And once the program find a non-digit after it finds the sequence of digits, I want it to break out of the loop using break; in the second if-statement (line 59). And I think it would be much easier if I can just write the condition using a variable.
What I want to say in line 59 is "If the var digit_flag is TRUE and the element in the array s is included in the var range(which is a number range), then break;"
Can it be done?
If it can't, why not?
int i = 0;
int size_of_s = 0;
int digit_flag = FALSE;
while (s[i] != '\0') {
if (s[i] == ' ') {
i++;
} else if (s[i] <= '9' && s[i] >= '0') {
size_of_s++;
i++;
digit_flag = TRUE;
}
if (digit_flag == TRUE && s[i] != range) {
break;
}
}
What I want to say in line 59 is "If the var digit_flag is TRUE and the element in the array s is included in the var range(which is a number range), then break;"
Can it be done?
As far as I know this can not be done in C.
If it can't, why not?
Because there is no relational or comparison operator in the C language which means "operand 1 is within the range of operand 2" (even if the second operand is an array). You need to use a logical AND (&&) of two conditions (>= A, <= B).
If you don't want to use a standard function - such as isdigit(), which will use the range 0-9 - you could use a macro
#define IS_IN_RANGE(x, min, max) (x >= min && x <= max)
or inline function.
static inline int is_in_range(int x, int min, int max) {
return (x >= min && x <= max);
}
If you want a "range" in C, you have to create one yourself:
// integer range class
// in this case it could also be a char range
struct int_range {
int start;
int end;
};
// range method to test for inclusinon
// in this case range could be passed as value efficiently, too,
// but passing as const pointer is more generic, so better example
bool int_range_contains(const struct int_range *range, int value) {
return value >= range->start && value <= range->end;
}
// example usage
void func(void) {
struct range digit_chars = { '0', '9' };
int character = 'a';
if (int_range_contains(&digit_chars, character)) {
// something
}
}
Of course this is a total overkill for this case. Your current if (s[i] <= '9' && s[i] >= '0') is better, and every C programmer immediately sees what's going on there.
Instead of
digit_flag == TRUE && s[i] != range
you can re-use what you already wrote
digit_flag == TRUE && !(s[i] <= '9' && s[i] >= '0')
If you want to extract the number sequence part in a string like
char str[]="hello1234isthesequence.";
you could just do
char seq[30];
if( sscanf(str, "%*[^0-9]%[0-9]", seq)==1 )
{
printf("\nThe sequence is: %s", seq);
}
where the %*[^0-9] is used to read everything from str[] till a non-digit character is encountered and the * is to suppress it ie, it will be discarded and won't be assigned to anywhere.
Next the %[0-9] will read the remaining part of the string in str till and excluding non-number and assign it to seq.
sscanf() will return the number of total successful assignments that it made, which in this case should be 1.
You may change the size of seq as per the size of the input string and change the width specifier in the format string of scanf() to avoid overflow.

strToInt function convert list of characters to integer in C

In C, I need a function that takes an alphanumerical list characters from 0-9 and converts it to an integer.
Code:
int strToInt(char string[])
{
int i, intValue, result = 0;
for (i = 0; string[i] > '0' && string[i] <= '9'; ++i)
{
intValue = string[i] - '0';
result = ???
}
return result;
}
What do I put in the ??? to make it work?
Try this:
result = result * 10 + intValue;
Also:
string[i] > '0'
in the for loop seems nasty - numbers can contain the digit 0, right? You may want to use
string[i] >= '0'
instead, or even better, without reinventing the wheel:
#include <ctype.h>
for (i = 0; isdigit(string[i]); ++i)
Well, your string is in decimal, base 10, and each digit in the string represents a position in a base 10 system. I.e. So you'd want to do
result = result * 10 + intValue;
Remember that '0' is also a digit, so you don't want to omit that one, Use string[i] >= '0'
If you are talking about base 10, you should probably include 0 also as a digit and hence
string[i] >= '0'
in your for loop. and usual place value calculation
result = result*10 + intValue;

Questions about a Kernighan and Ritchie Excercise 2-3

I'm trying to write a program in C that converts hexadecimal numbers to integers. I've written successfully a program that converts octals to integers. However, the problems begin once I start using the letters (a-f). My idea for the program is ads follows:
The parameter must be a string that starts with 0x or 0X.
The parameter hexadecimal number is stored in a char string s[].
The integer n is initialized to 0 and then converted as per the rules.
My code is as follows (I've only read up to p37 of K & R so don't know much about pointers) :
/*Write a function htoi(s), which converts a string of hexadecimal digits (including an optional 0x or 0X) into its equivalent integer value. The allowable digits are 0 through 9, a through f, and A through F.*/
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
int htoi(const char s[]) { //why do I need this to be constant??
int i;
int n = 0;
int l = strlen(s);
while (s[i] != '\0') {
if ((s[0] == '0' && s[1] == 'X') || (s[0] == '0' && s[1] == 'x')) {
for (i = 2; i < (l - 1); ++i) {
if (isdigit(s[i])) {
n += (s[i] - '0') * pow(16, l - i - 1);
} else if ((s[i] == 'a') || (s[i] == 'A')) {
n += 10 * pow(16, l - i - 1);
} else if ((s[i] == 'b') || (s[i] == 'B')) {
n += 11 * pow(16, l - i - 1);
} else if ((s[i] == 'c') || (s[i] == 'C')) {
n += 12 * pow(16, l - i - 1);
} else if ((s[i] == 'd') || (s[i] == 'D')) {
n += 13 * pow(16, l - i - 1);
} else if ((s[i] == 'e') || (s[i] == 'E')) {
n += 14 * pow(16, l - i - 1);
} else if ((s[i] == 'f') || (s[i] == 'F')) {
n += 15 * pow(16, l - i - 1);
} else {
;
}
}
}
}
return n;
}
int main(void) {
int a = htoi("0x66");
printf("%d\n", a);
int b = htoi("0x5A55");
printf("%d\n", b);
int c = htoi("0x1CA");
printf("%d\n", c);
int d = htoi("0x1ca");
printf("%d\n", d);
}
My questions are:
1. If I don't use const in the argument for htoi(s), i get the following warnings from the g++ compiler :
2-3.c: In function ‘int main()’: 2-3.c:93:20: warning: deprecated
conversion from string constant to ‘char*’ [-Wwrite-strings]
2-3.c:97:22: warning: deprecated conversion from string constant to
‘char*’ [-Wwrite-strings] 2-3.c:101:21: warning: deprecated conversion
from string constant to ‘char*’ [-Wwrite-strings] 2-3.c:105:21:
warning: deprecated conversion from string constant to ‘char*’
[-Wwrite-strings]
Why is this?
2.Why is my program taking so much time to run? I haven't seen the results yet.
3.Why is it that when I type in cc 2-3.c instead of g++ 2-3.c in the terminal, I get the following error message:
"undefined reference to `pow'"
on every line that I've used the power function?
4. Please do point out other errors/ potential improvements in my program.
If I don't use const in the argument for htoi(s), i get the following warnings from the g++ compiler
The const parameter should be there, because it is regarded as good and proper programming to never typecast away const from a pointer. String literals "..." should be treated as constants, so if you don't have const as parameter, the compiler thinks you are casting away the const qualifier.
Furthermore, you should declare all pointer parameters that you don't intend to modify the contents of as const, Google the term const correctness.
Why is my program taking so much time to run? I haven't seen the results yet.
I think mainly because you have made an initialization goof-up. int i; i contains rubbish. Then while (s[rubbish_value] != '\0'). This function can be written a whole lot better too. Start by checking for the 0x in the start of the string, if they aren't there, signal some error (return NULL?), otherwise discard them. Then start one single loop after that, you don't need 2 loops.
Note that the pow() function deals with float numbers, which will make your program a slight bit slower. You could consider using an integer-only version. Unfortunately there is no such function in standard C, so you will have to found one elsewhere.
Also consider the function isxdigit(), a standard function in ctype.h, which checks for digits 0-9 as well as hex letters A-F or a-f. It may however not help with performance, as you will need to perform different calculations for digits and letters.
For what it is worth, here is a snippet showing how you can convert a single char to a hexadecimal int. It is not the most optimized version possible, but it takes advantage of available standard functions, for increased readability and portability:
#include <ctype.h>
uint8_t hexchar_to_int (char ch)
{
uint8_t result;
if(isdigit(ch))
{
result = ch - '0';
}
else if (isxdigit(ch))
{
result = toupper(ch) - 'A' + 0xA;
}
else
{
// error
}
return result;
}
Don't use a C++ compiler to compile a C program. That's my first advice to you.
Secondly const in a function parameter for a char * ensures that the programmer doesn't accidentally modify the string.
Thirdly you need to include the math library with -lm as stated above.
a const char[] means that you cannot change it in the function. Casting from a const to not-const gives a warning. There is much to be said about const. Check out its Wikipedia page.
--
Probably, cc doesn't link the right libraries. Try the following build command: cc 2-3.c -lm
Improvements:
Don't use pow(), it is quite expensive in terms of processing time.
Use the same trick with the letters as you do with the numbers to get the value, instead of using fixed 'magic' numbers.
You don't need the last else part. Just leave it empty (or put an error message there, because those characters aren't allowed).
Good luck!
About my remark about the pow() call (with the use of the hexchar_to_int() function described above, this is how I'd implement this (without error checking):
const char *t = "0x12ab";
int i = 0, n = 0;
int result = 0;
for (i = 2; i < strlen(t); i++) {
n = hexchar_to_int(t[i]);
result |= n;
result <<= 4;
}
/* undo the last shift */
result >>= 4;
I just worked through this exercise myself, and I think one of the main ideas was to use the knowledge that chars can be compared as integers (they talk about this in chapter 2).
Here's my function for reference. Thought it may be useful as the book doesn't contain answers to exercises.
int htoi(char s[]) {
int i = 0;
if(s[i] == '0') {
++i;
if(s[i] == 'x' || s[i] == 'X') {
++i;
}
}
int val = 0;
while (s[i] != '\0') {
val = 16 * val;
if (s[i] >= '0' && s[i] <= '9')
val += (s[i] - '0');
else if (s[i] >= 'A' && s[i] <= 'F')
val += (s[i] - 'A') + 10;
else if (s[i] >= 'a' && s[i] <= 'f')
val += (s[i] - 'a') + 10;
else {
printf("Error: number supplied not valid hexadecimal.\n");
return -1;
}
++i;
}
return val;
}
Always init your variables int i=0, otherwise i will contain a garbage value, could be any number, not necessary 0 as you expect. You're running the while statement in an infinite loop, that's why it takes forever to get the results, print i to see why. Also, add a break if the string doesn't start with 0x, will avoid the same loop issue when the user is used on a random string. As others mention you need to import the library containing pow function and declare your string with const to get rid of the warning.
This is my version of program for the question above. It converts the string of hex into decimal digits irrespective of optional prefix(0x or 0X).
4 important library functions used are strlen(s), isdigit(c), isupper(c), isxdigit(c), pow(m,n)
Suggestions to improve the code are welcome :)
/*Program - 5d Function that converts hex(s)into dec -*/
#include<stdio.h>
#include<stdlib.h>
#include<math.h> //Declares mathematical functions and macros
#include<string.h> //Refer appendix in Page 249 (very useful)
#define HEX_LIMIT 10
int hex_to_dec(char hex[]) //Function created by me :)
{
int dec = 0; //Initialization of decimal value
int size = strlen(hex); //To find the size of hex array
int temp = size-1 ; //Pointer pointing the right element in array
int loop_limit = 0; //To exclude '0x' or 'OX' prefix in input
if(hex[0]=='0' && ((hex[1]=='x') || (hex[1]=='X')))
loop_limit = 2;
while(temp>=loop_limit)
{
int hex_value = 0; //Temporary value to hold the equivalent hex digit in decimal
if(isdigit(hex[temp]))
hex_value = (hex[(temp)]-'0') ;
else if(isxdigit(hex[temp]))
hex_value = (toupper(hex[temp])-'A' + 10);
else{
printf("Error: No supplied is not a valid hex\n\n");
return -1;
}
dec += hex_value * pow(16,(size-temp-1)); //Computes equivalent dec from hex
temp--; //Moves the pointer to the left of the array
}
return dec;
}
int main()
{
char hex[HEX_LIMIT];
printf("Enter the hex no you want to convert: ");
scanf("%s",hex);
printf("Converted no in decimal: %d\n", hex_to_dec(hex));
return 0;
}

How to create a function to count occurrences of each letter?

In C, I need to create a function that, for an input, will count and display the number of times each letter occurs.
For input of "Lorem ipsum dolor sit amet", the function should return something similar to:
a: 0
b: 0
c: 0
d: 1
e: 2
f: 0
...
So you will basically need to read through the entire file char-by-char. Assuming that you know how file-reading works, you will need to do something like (apologies, been a while since I did C):
if (isalpha(ch)) {
count[ch-'a']++;
}
/* rest of code where char pointer is moved on etc. */
You will need to import the ctype library for that:
#include <ctype.h>
** forgot to mention, assumed you would deduce the following: ch is your pointer to the currently read in character, while count[] is an int[], initialized to all zeros with a size of (26 * 2) = 52 to cater for both upper and lowercase. If upper and lower-case should be treated the same, you can use the tolower(int c) function also included in the ctype library. In this case you only need a 26 size array.
if (isalpha(ch)) {
count[tolower(ch)-'a']++;
}
Then the count[] should contain the counts for each character.
/* ***** */
If you wanted to do this with only the stdio.h library, you can implement the two functions used from the ctype.h library.
A simple implementation of the isalpha(int c) function could be something like:
if (((int)c >= 'a' && (int)c <= 'z') || ((int)c >= 'A' && (int)c <= 'Z') {
return TRUE;
} else {
return FALSE;
}
(where TRUE and FALSE are of type your return type and something you defined).
And a REALLY simple version of tolower could be something like:
if ((int)c >= 'A' && (int)c <= 'Z') {
return (int)c - 'a';
} else {
return (int)c;
}
You could probably do without all the casts...
hints:
char c[26] = { 0 }; // init
// read each input chars
++c[input-'a'];
I would have an array (of the size equal to char domain) and increment the count at apropriate position.
count[ch]++;
Just in case you are concerned with speed:
unsigned int chars[255], *p = text;
while(*p)
chars[*p]++;
for(int i = 0; i < 255; i++)
if(i > ('A' - 1) && i < ('Z' + 1))
printf("%c) %u/n", i, chars[i];
Sorry for the "/n" but my mac pro does not have the right character on its keyboard...

Resources