Hello I would like to check for a float number in string
#include<stdio.h>
#include <math.h>
#include <ctype.h>
#include <stdlib.h>
int main(void)
{
char qihjuq[] = "a s d a s d g g 1 2 3 1 2 3 5 5.4 d 10.4";
int num[256];
float digit[256];
char let[256] = {"0"};
int lcounter =0;
int ncounter =0;
int dcounter =0;
for(int i =0; i< sizeof qihjuq; i++)
{
if(isalpha(*(qihjuq+i))) {
let[lcounter] = *(qihjuq + i);
lcounter++;
}
else if(isdigit(*(qihjuq+i)) && *(qihjuq+i+1) != '.') {
num[ncounter] = *(qihjuq + i);
ncounter++;
}
else if(roundf(*(qihjuq+i)) != *(qihjuq+i)) {
digit[dcounter] = *(qihjuq + i);
dcounter++;
}
}
printf("The letters are: \n");
for(int i =0; i< lcounter; i++)
printf("%c ",let[i]);
printf("The whole numbers are: \n");
for(int i =0; i< ncounter; i++)
printf("%c ",num[i]);
}
The problem lies in the second and third if
else if(isdigit(*(qihjuq+i)) && *(qihjuq+i+1) != '.') {
num[ncounter] = *(qihjuq + i);
ncounter++;
}
else if(roundf(*(qihjuq+i)) != *(qihjuq+i)) {
digit[dcounter] = *(qihjuq + i);
dcounter++;
}
where the program has to detect whether the is float or integer. The problem is that the program is detecting 10.4 as individual characters which in turn puts 1 0 4 in the whole number to try to negate this I added a detection for . but still has logical errors since the condition does not include the numbers behind the .
like this:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main(void){
char qihjuq[] = "a s d a s d g g 1 2 3 1 2 3 5 5.4 d 10.4";
int num[256];
float digit[256];
char let[256];
int lcounter =0;
int ncounter =0;
int dcounter =0;
for(int i = 0; i < sizeof(qihjuq) -1; i++){
if(isspace(qihjuq[i]))
continue;//skip spaces
char work[256] = {0};
for(int j = 0; qihjuq[i] && !isspace(qihjuq[i]); ++j, ++i)
work[j] = qihjuq[i];//Extraction
--i;//for next loop
if(isalpha(*work) && !work[1]) {//one letter
let[lcounter++] = *work;
} else {
char *p = work;
int n = strtol(p, &p, 10);
if(!*p)//convert to int succeeded (Not strict)
num[ncounter++] = n;
else {
p = work;
float f = strtod(p, &p);
if(!*p)//convert to float succeeded (Not strict)
digit[dcounter++] = f;
}
}
}
printf("The letters are: \n");
for(int i = 0; i < lcounter; i++)
printf("%c ", let[i]);
printf("\nThe whole numbers are: \n");
for(int i = 0; i < ncounter; i++)
printf("%d ", num[i]);
puts("");
}
I do not understand your approach.
You have – let's call it – tokens in a string separated by spaces. You can neither detect the kind of a token nor the value of that token by simply looking on one character.
You have two options: (Logically they are the same, but the implementation is different.)
You iterate over the string extracting the tokens and then iterate over each token to detect its kind.
You iterate over the string and recursively iterate over a token.
Like so (typped in browser)
char *char_ptr = qihjuq;
do
{
if( char_ptr == ' ')
{
continue
}
// iterate overe the next token
int char_set = 0x0;
char * start_ptr = char_ptr; // The start of an item
do
{
if( isdigit( *char_ptr) )
{
char_set |= 0x01; // contains digit
}
else if( *char_ptr == '.' )
{
char_set |= 0x02; // contains period
}
else if( isalpha( *char_ptr ))
{
char_set |= 0x04;
}
break; // any other character breaks item
} while( *char_ptr++ );
// integers have 0x01, floats have 0x3. Other values are alphas or alphanumerics
// you can store the result into an array, do some processing with them or whatever you want. start_ptr points to the beginning of the item_char_ptr to one char after the end.
} while ( *char_ptr++ )
Likely there are some bugs, but this is the structure.
Just read a double with strtod().
If it works, the end pointer points to the position to read from; if it doesn't work advance by 1.
Keep at it until the end of the string
/* code untested */
double x;
char *end
char qihjuq[] = "a s d a s d g g 1 2 3 1 2 3 5 5.4 d 10.4";
char *p = qihjuq;
while (*p) {
errno = 0;
x = strtod(p, &end);
if (errno) {
p += 1;
} else {
printf("found %f\n", x);
p = end;
}
}
Related
I am self teaching C programming.
I am trying to count number of int present in given string which are separated by space.
exp:
input str = "1 2 11 84384 0 212"
output should be: 1, 2, 11, 84384, 0, 212
total int = 6
When I try. It gives me all the digits as output which make sense since I am not using a right approach here.
I know in python I can use str.split (" ") function which can do my job very quickly.
But I want to try something similar in C. Trying to create my own split method.
#include <stdio.h>
#include <string.h>
void count_get_ints(const char *data) {
int buf[10000];
int cnt = 0, j=0;
for (int i=0; i<strlen(data); i++) {
if (isspace(data[i] == false)
buf[j] = data[i]-'0';
j++;
}
printf("%d", j);
}
// when I check the buffer it includes all the digits of the numbers.
// i.e for my example.
// buf = {1,2,1,1,8,4,3,8,4,0,2,1,2}
// I want buf to be following
// buf = {1,2,11,84384,0,212}
I know this is not a right approach to solve this problem. One way to keep track of prev and dynamically create a memory using number of non space digits encountered.
But I am not sure if that approach helps.
You want to build your number incrementally until you hit a space, then put that into the array. You can do this by multiplying by 10 then adding the next digit each time.
void count_get_ints(const char *data) {
int buf[10000];
int j = 0;
int current_number = 0;
// Move this outside the loop to eliminate recalculating the length each time
int total_length = strlen(data);
for (int i=0; i <= total_length; i++) {
// Go up to 1 character past the length so you
// capture the last number as well
if (i == total_length || isspace(data[i])) {
// Save the number, and reset it
buf[j++] = current_number;
current_number = 0;
}
else {
current_number *= 10;
current_number += data[i] - '0';
}
}
}
I think strtok will provide a cleaner solution, unless you really want to iterate over every char in the string. It has been a while since I did C, so please excuse any errors in the code below, hopefully it will give you the right idea.
#include <stdio.h>
#include <stdlib.h>
int main() {
char str[19] = "1 2 11 84384 0 212";
const char s[2] = " ";
char *token;
int total;
total = 0;
token = strtok(str, s);
while (token != NULL) {
printf("%s\n", token);
total += atoi(token);
token = strtok(NULL, s);
}
printf("%d\n", total);
return 0;
}
You can check the ascii value of each character by doing c-'0'. If it's between [0,9], then it's an integer. By having a state variable, when you're inside an integer by checking if a given character is a number of space, you can keep track of the count by ignoring white space. Plus you don't need a buffer, what happens if data is larger than 10,000, and you write pass the end of the buffer?, undefined behavior will happen. This solution doesn't require a buffer.
Edit, the solution now prints the integers that are in the string
void count_get_ints(const char *data) {
int count = 0;
int state = 0;
int start = 0;
int end = 0;
for(int i = 0; i<strlen(data); i++){
int ascii = data[i]-'0';
if(ascii >= 0 && ascii <= 9){
if(state == 0){
start = i;
}
state = 1;
}else{
//Detected a whitespace
if(state == 1){
count++;
state = 0;
end = i;
//Print the integer from the start to end spot in data
for(int j = start; j<end; j++){
printf("%c",data[j]);
}
printf(" ");
}
}
}
//Check end
if(state == 1){
count++;
for(int j = start; j<strlen(data); j++){
printf("%c",data[j]);
}
printf(" ");
}
printf("Number of integers %d\n",count);
}
I believe the standard way of doing this would be using sscanf using the %n format specifier to keep track of how much of the string is read.
You can start with a large array to read into -
int array[100];
Then you can keep reading integers from the string till you can't read anymore or you are done reading 100.
int total = 0;
int cont = 0;
int ret = 1;
while(ret == 1 && total < 100) {
ret = sscanf(input, "%d%n", &array[total++], &cont);
input += cont;
}
total--;
printf("Total read = %d\n", total);
and array contains all the numbers read.
Here is the DEMO
Example using strtol
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <errno.h>
#include <ctype.h>
int count_get_ints(int output[], int output_size, const char *input) {
const char *p = input;
int cnt;
for(cnt = 0; cnt < output_size && *p; ++cnt){
char *endp;
long n;
errno = 0;
n = strtol(p, &endp, 10);
if(errno == 0 && (isspace((unsigned char)*endp) || !*endp) && INT_MIN <= n && n <= INT_MAX){
output[cnt] = n;
while(isspace((unsigned char)*endp))
++endp;//skip spaces
p = endp;//next parse point
} else {
fprintf(stderr, "invalid input '%s' in %s\n", p, __func__);
break;
}
}
return cnt;
}
int main(void) {
const char *input = "1 2 11 84384 0 212";
int data[10000];
int n = sizeof(data)/sizeof(*data);//number of elements of data
n = count_get_ints(data, n, input);
for(int i = 0; i < n; ++i){
if(i)
printf(", ");
printf("%d", data[i]);
}
puts("");
}
Assuming you don't have any non-numbers in your string, you can just count the number of spaces + 1 to find the number of integers in the string like so in this pseudo code:
for(i = 0; i < length of string; i++) {
if (string x[i] == " ") {
Add y to the list of strings
string y = "";
counter++;
}
string y += string x[i]
}
numberOfIntegers = counter + 1;
Also, this reads the data between the white spaces. Keep in mind this is pseudo code, so the syntax is different.
I'm learning C and have some struggles.I have to make a program , which becomes a text (max 80 chars) and put the words from text in a char words[80][80] (every word must be only single time in this array! it is also defined as global) and count of times every word comes in the text in a int count[] (Index must be same as this from words[][]).
The function is called int extract_and_count(char *source,int *count).
I wrote some code ,but I'm not sure how exactly to implement this function.Can someone help me?
I'm also new to stackoverflow so if I have made any mistake, sorry.
Thats some of the code but its not to the end:
int extract_and_count(char *source,int *count){
char token[80][80];
char *p;
int i = 0;
p = strtok(source, " ");
while( p != NULL ){
strcpy(token[i],p);
printf("%s\n",*(token+i));
i++;
p = strtok(NULL , " ");
}
char word;
int value = 0, j;
for(i = 0 ; i < 80 ; i++){
word = token[i];
for(j = 0 ; j < 80 ; j++){
if(strcmp(word,token[i])==0){
value++;
}
}
}
return 1;
}
You need to check if a word has been found already. If so, just increment the global counter. Otherwise, copy the new word to the global array of strings.
Something like:
#include <stdio.h>
#include <string.h>
// Global variables to hold the results
char word[80][81];
int count[80] = { 0 };
int extract_and_count(char *source,int *strings_cnt){
char token[80][81];
char *p;
int i = 0;
// Find all words in the input string
p = strtok(source, " ");
while( p != NULL ){
strcpy(token[i],p);
// printf("%s\n",*(token+i));
i++;
p = strtok(NULL , " ");
}
// Find unique words and count the number a word is repeated
*strings_cnt = 0;
int j,k;
// Iterator over all words found in the input string
for(j = 0 ; j < i ; j++){
// Check if the word is already detected once
int found = 0;
for(k = 0 ; k < *strings_cnt ; k++){
if (strcmp(word[k], token[j]) == 0)
{
// The word already exists - increment count
found = 1;
count[k]++;
break;
}
}
if (!found)
{
// New word - copy it and set count to 1
strcpy(word[*strings_cnt], token[j]);
count[*strings_cnt] = 1;
(*strings_cnt)++;
}
}
return 1;
}
int main(void)
{
char s[] = "c language is difficult c is also fun";
int c, i;
printf("Searching: %s\n", s);
extract_and_count(s, &c);
printf("Found %d different words\n", c);
for (i=0; i<c; i++)
{
printf("%d times: %s\n", count[i], word[i]);
}
return 0;
}
Output:
Searching: c language is difficult c is also fun
Found 6 different words
2 times: c
1 times: language
2 times: is
1 times: difficult
1 times: also
1 times: fun
Above I tried to follow your codes style but I like to add these comments:
1) You don't really need the token array. The first loop can be changed so that it updates the final result directly.
2) Don't use global variable
3) The code can't handle normal separators like , . : and so on
4) You should put the word and the count into a struct.
Taken comment 1,2 and 4 in to consideration, the code could be:
#include <stdio.h>
#include <string.h>
// Global variables to hold the results
struct WordStat
{
char word[81];
int count;
};
int extract_and_count(char *source,int *strings_cnt, struct WordStat* ws, int max){
char *p;
int i = 0;
int k;
*strings_cnt = 0;
// Find all words in the input string
p = strtok(source, " ");
while( p != NULL ){
// Check if the word is already detected once
int found = 0;
for(k = 0 ; k < *strings_cnt ; k++){
if (strcmp(ws[k].word, p) == 0)
{
// The word already exists - increment count
found = 1;
ws[k].count++;
break;
}
}
if (!found)
{
// New word - copy it and set count to 1
strcpy(ws[*strings_cnt].word, p);
ws[*strings_cnt].count = 1;
(*strings_cnt)++;
}
i++;
p = strtok(NULL , " ");
}
return 1;
}
#define MAX_WORDS 80
int main(void)
{
struct WordStat ws[MAX_WORDS];
char s[] = "c language is difficult c is also fun";
int c, i;
printf("Searching: %s\n", s);
extract_and_count(s, &c, ws, MAX_WORDS);
printf("Found %d different words\n", c);
for (i=0; i<c; i++)
{
printf("%d times: %s\n", ws[i].count, ws[i].word);
}
return 0;
}
while( p != NULL ){
strcpy(token[i],p);
printf("%s\n",*(token+i));
i++;
p = strtok(NULL , " "); --> here you are just splitting the words
}
Now token will contain all the words in splitted manner, not as per your requirement of "each word only once". You can compare and copy the unique words to another array and in the same loop, you can count and update the count array.
Note: You should not use one counter variable on the whole, the array of counter only shall be used to count the words.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define NUM_OF_WORDS_MAX 80
#define MAX_WORD_LENGTH 79
#define S_(x) #x
#define S(x) S_(x) //number literal convert to string
char words[NUM_OF_WORDS_MAX][MAX_WORD_LENGTH+1];
int Words_entry = 0;
static inline int hash(const char *str){
return (tolower(*str) - 'a')*3;//3:(NUM_OF_WORDS_MAX / 26), 26 : a-z
}
char *extract(char **sp){//extract word
char *p = *sp;
while(*p && !isalpha(*p))//skip not alpha
++p;
if(!*p)
return NULL;
char *ret = p;//first word
while(*p && isalpha(*p))//skip alpha
++p;//*p = tolower(*p);
if(!*p){
*sp = p;
} else {
*p = '\0';
*sp = ++p;//rest
}
return ret;
}
int extract_and_count(char *source, int *count){
char *sp = source;
char *word;
int word_count = 0;
while(word = extract(&sp)){
if(Words_entry == NUM_OF_WORDS_MAX){
fprintf(stderr, "words table is full.\n");
return word_count;
}
int index = hash(word);
while(1){
if(*words[index]){
if(strcasecmp(words[index], word) == 0){//ignore case
++count[index];
break;
}
if(++index == NUM_OF_WORDS_MAX){
index = 0;
}
} else {
strcpy(words[index], word);
count[index] = 1;
++Words_entry;
break;
}
}
++word_count;
}
return word_count;
}
int main(void){
int count[NUM_OF_WORDS_MAX] = {0};
char text[MAX_WORD_LENGTH+1];
while(1==scanf("%" S(MAX_WORD_LENGTH) "[^\n]%*c", text)){//end if only enter press.
extract_and_count(text, count);
}
//print result
for(int i = 0; i < NUM_OF_WORDS_MAX; ++i){
if(*words[i]){
printf("%s : %d\n", words[i], count[i]);
}
}
return 0;
}
I need to convert the string "12345678" to the value 00010010001101000101011001111000 (the value in binary only without the zeroes on the left).
So I have written this code in c, the problem is that when I run it does nothing, just waits like there is an error until I stop it manually.
Any ideas?
#include <stdio.h>
#include <string.h>
void reduce(char string[]) {
int i=0, j=0, k=0, cnt=0, tmp=4, num;
char arr[4], result[4*strlen(string)];
for (i=0; i<strlen(string); i++) {
num = atoi(string[i]);
while (num != 0) {
arr[j++] = num%2;
num = num/2;
tmp--;
}
while (tmp != 0) {
arr[j++] = 0;
tmp--;
}
j--;
for (k=i*4; k<(i*4+4); k++) {
result[k++] = arr[j--];
}
j = 0;
tmp = 4;
}
printf("The result is: \n");
for (i=0; i<4*strlen(result); i++) {
printf("%d",result[i]);
}
printf("\n");
}
int main() {
char c[8] = "12345678";
reduce(c);
return 0;
}
Lots of small errors in your code, which makes it hard to pin-point a single error. Main problem seems to be you are confusing binary numbers (0, 1) with ASCII digits ("0", "1") and are mis-using string functions.
as mentioned elsewhere, char c[8] = .. is wrong.
atoi(string[i]) cannot work; it expects a string, not a char. Use `num = string[i]-'0';
arr[..] gets the value 'num%2, that is, a numerical value. Better to use '0'+num%2 so it's a character string.
you increment k in result[k++] inside a loop that already increments k
add result[k] = 0; at the end before printing, so strlen works correctly
4*strlen(result) is way too much -- the strlen is what it is.
you might as well do a simple printf("%s\n", result);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void reduce(char string[]) {
int i=0, j=0, k=0, cnt=0, tmp=4, num;
char arr[5], result[4*strlen(string)+1];
for (i=0; i<strlen(string); i++) {
num = string[i]-'0';
while (num != 0) {
arr[j++] = '0'+num%2;
num = num/2;
tmp--;
}
while (tmp != 0) {
arr[j++] = '0';
tmp--;
}
arr[j] = 0;
j--;
for (k=i*4; k<(i*4+4); k++) {
result[k] = arr[j--];
}
j = 0;
tmp = 4;
}
result[k] = 0;
printf("The result is: \n");
for (i=0; i<strlen(result); i++) {
printf("%c",result[i]);
}
printf("\n");
}
int main() {
char c[] = "12345678";
reduce(c);
return 0;
}
.. resulting in
The result is:
00010010001101000101011001111000
It seems from your example that the conversion you are attempting is to binary coded decimal rather than binary. That being the case your solution is somewhat over-complicated; you simply need to convert each digit to its integer value then translate the bit pattern to ASCII 1's and 0's.
#include <stdio.h>
void reduce( const char* c )
{
for( int d = 0; c[d] != 0; d++ )
{
int ci = c[d] - '0' ;
for( unsigned mask = 0x8; mask != 0; mask >>= 1 )
{
putchar( (ci & mask) == 0 ? '0' : '1' ) ;
}
}
}
On the other hand if you did intend a conversion to binary (rather than BCD), then if the entire string is converted to an integer, you can directly translate the bit pattern to ASCII 1's and 0's as follows:
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
void reduce( const char* c )
{
unsigned ci = (unsigned)atoi( c ) ;
static const int BITS = sizeof(ci) * CHAR_BIT ;
for( unsigned mask = 0x01 << (BITS - 1); mask != 0; mask >>= 1 )
{
putchar( (ci & mask) == 0 ? '0' : '1' ) ;
}
}
In your main(), do either
char c[ ] = "12345678";
or
char c[9] = "12345678";
if you want to use c as a string. Otherwise, it does not have enough space to store the terminating null character.
Here, I took the liberty to modify the code accordingly to work for you. Check the below code. Hope it's self-explanatoty.
#include <stdio.h>
#include <string.h>
void reduce(char string[]) {
int i=0, j=0, k=0, cnt=0, count = 0; //count added, tmp removed
char arr[4], result[ (4*strlen(string) )+ 1], c; //1 more byte space to hold null
for (i=0; i<strlen(string); i++) {
c = string[i];
count = 4;
while (count != 0) { //constant iteration 4 times baed on 9 = 1001
arr[j++] = '0' + (c%2); //to store ASCII 0 or 1 [48/ 49]
c = c/2;
count--;
}
/* //not required
while (tmp >= 0) {
arr[j++] = 0;
tmp--;
}
*/
j--;
for (k=(i*4); k<((i*4) +4); k++) {
result[k] = arr[j--];
}
j = 0;
memset (arr, 0, sizeof(arr));
}
result[k] = 0;
printf("The result is: %s\n", result); //why to loop when we've added the terminating null? print directly.
/*
for (i=0; i< strlen(result); i++) {
printf("%c",result[i]);
}
printf("\n");
*/
}
int main() {
char c[ ] = "12345678";
reduce(c);
return 0;
}
Output:
[sourav#broadsword temp]$ ./a.out
The result is: 00010010001101000101011001111000
Convert your string to an integer using int num = atoi(c).
Then do
int binary[50];
int q = num,i=0;
while(q != 0)
{
binary[i++] = q%2;
q = q/2;
}
Printing your binary array is reverse order will have your binary equivalent.
Full program:
#include<stdio.h>
int main(){
char c[100];
int num,q;
int binary[100],i=0,j;
scanf("%d",c);
num = atoi(c);
q = num;
while(q!=0){
binary[i++]= q % 2;
q = q / 2;
}
for(j = i -1 ;j>= 0;j--)
printf("%d",binary[j]);
return 0;
}
You can use the below reduce function.
void reduce(char string[])
{
unsigned int in = atoi(string) ;
int i = 0, result[32],k,j;
while (in > 0) {
j = in % 10;
k = 0;
while (j > 0) {
result[i++] = j % 2;
j = j >> 1;
k++;
}
while (k < 4) {
result[i++] = 0;
k++;
}
in = in/10;
}
printf("Result\n");
for(--i;i >= 0; i--) {
printf("%d", result[i]);
}
printf("\n");
}
For 12345678
the output would be 00010010001101000101011001111000, where each character is printed in its binary format.
It might need some adjustments, but it does the job as it is.
#include <stdio.h>
#include <stdlib.h>
int
main(void)
{
int i;
int n;
char *str = "12345678";
const int bit = 1 << (sizeof(n)*8 - 1);
n = atoi(str);
for(i=0; i < sizeof(n)*8 ; i++, n <<= 1)
n&bit ? printf("1") : printf("0");
return 0;
}
I'm trying to create a function that, given two C strings, it spits back the number of consecutive character overlap between the two strings.
For example,
String 1: "Today is monday."
String 2: " is monday."
The overlap here would be " is monday.", which is 11 characters (it includes the space and '.').
If you need something more efficient, consider that a partial mismatch between Strings 1 and 2 means you can jump the length of the remainder of String 2 along String 1. This means you don't need to search the entirety of String 1.
Take a look at the Boyer-Moore algorithm. Though it is used for string searching, you could implement this algorithm for finding the maximum-length substring using String 2 as your pattern and String 1 as your target text.
There is probably a more efficient way to do this, but here's a simple approach:
#include <string.h>
int main() {
char s1[17] = "Today is monday.";
char s2[12] = " is monday.";
int max = 0;
int i_max = -1;
int j_max = -1;
int i = 0, j = 0, k=0;
int endl = 0, sl1, sl2;
char *ss1, *ss2;
for(i = 0; i < strlen(s1)-1; i++) {
ss1 = s1+i;
sl1 = strlen(ss1);
if(max >= sl1) {
break; // You found it.
}
for(j = 0; j < strlen(s2)-1; j++) {
ss2 = s2+j;
sl2 = strlen(ss2);
if(max >= sl2) {
break; // Can't find a bigger overlap.
}
endl = (sl1 > sl2)?sl2:sl1;
int n_char = 0;
for(k = 0; k < endl+1; k++) {
// printf("%s\t%s\n", ss1+k, ss2+k); // Uncomment if you want to see what it compares.
if(ss1[k] != ss2[k] || ss1[k] == '\0') {
n_char = k;
break;
}
}
if(n_char > max) {
max = n_char;
i_max = i;
j_max = j;
}
}
}
char nstr[max+1];
nstr[max] = '\0';
strncpy(nstr, s1+i_max, max);
printf("Maximum overlap is %d characters, substring: %s\n", max, nstr);
return 0;
}
Update: I have fixed the bugs. This definitely compiles. Here is the result: http://codepad.org/SINhmm7f
The problems were that endl was defined wrong and I wasn't checking for end-of-line conditions.
Hopefully the code speaks for itself.
Here is my solution, it will return the position of the overlap starting point, it's a bit complex, but that's how it's done in C:
#include <string.h>
int FindOverlap (const char * a, const char * b)
{
// iterators
char * u = a;
char * v = b;
char * c = 0; // overlap iterator
char overlapee = 'b';
if (strlen(a) < strlen(b)) overlapee = 'a';
if (overlapee == 'b')
{
while (*u != '\0')
{
v = b; // reset b iterator
c = u;
while (*v != '\0')
{
if (*c != *v) break;
c++;
v++;
}
if (*v == '\0') return (u-a); // return overlap starting point
}
}
else if (overlapee == 'a')
{
while (*v != '\0')
{
u = a; // reset b iterator
c = v;
while (*u != '\0')
{
if (*c != *u) break;
c++;
u++;
}
if (*v == '\0') return (v-b); // return overlap starting point
}
}
return (-1); // not found
}
I have written a program in C running on UNIX which counts the number of each letters in a input text file. For a file like this:
'The cat sat on the green mat'
The output would be like this:
The letter ’a’ occurs 3 times.
The letter ’c’ occurs 1 times.
The letter ’e’ occurs 4 times.
The letter ’g’ occurs 1 times.
The letter ’h’ occurs 2 times.
The letter ’m’ occurs 1 times.
The letter ’n’ occurs 2 times.
The letter ’o’ occurs 1 times.
The letter ’r’ occurs 1 times.
The letter ’s’ occurs 1 times.
The letter ’t’ occurs 5 times.
5 *
4 * *
4 * *
3 * * *
3 * * *
2 * * * * *
2 * * * * *
1 * * * ** *** ***
1 * * * ** *** ***
0 **************************
0 **************************
... abcdefghijklmnopqrstuvwxyz
Where the graph represents the amount of times a letter appears. (If it is more than 10, i simply put a '+' after the 10th row). The code I've currently written to achieve this is as follows:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
void drawGraph(int letters[26], char alpha[26]);
void printLetters(int letters[26], char alpha[26]);
void getLetters(FILE *fp, int letters[26], char alpha[26]);
int main(int argc, char *argv[]) {
FILE *fp;
int letters[26] = { 0 };
char alpha[26] = { 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z' };
int indexedAlpha[256] = { 0 };
int j = 1;
for (i = 97; i <= 127; i++)
{
indexedAlpha[i] = j;
j++;
}
//open file
if ((fp = fopen(argv[1], "r")) == NULL)
{
perror("Cannot open file");
exit(EXIT_FAILURE);
}
getLetters(fp, letters, alpha);
printLetters(letters, alpha);
printf("\n");
drawGraph(letters, alpha);
printf("\n");
return EXIT_SUCCESS;
}
void getLetters(FILE *fp, int letters[26], char alpha[26]) {
int c;
for (int i = 0; (c = fgetc(fp)) != EOF; i++)
{
c = fgetc(fp);
if ( isalpha(c) )
{
for ( int j = 0; j < 26; j++ ) //find which letter it is
{
if( c == alpha[j] )
{
letters[j]++;
break;
}
}
}
}
}
void printLetters(int letters[26], char alpha[26]) {
for( int i = 0; i < 26; i++ )
{
if(letters[i] != 0){
printf("The letter '%c' occurs %d times.\n", alpha[i], letters[i]);
}
}
}
void drawGraph(int letters[26], char alpha[26]) {
int x = 11;
int y;
while(x >= 0)
{
y = 0;
while (y < 2)
{
if (x == 10)
{
printf(" %d ", x);
}
else if (x == 11)
{
printf(" ");
}
else
{
printf(" %d ", x);
}
for( int i = 0; i < 26; i++ )
{
if(letters[i] > 10)
{
printf("+");
letters[i] = 10;
y++; // Break out of while loop
}
else if(letters[i] == x)
{
printf("*");
}
else
{
printf(" ");
}
if (letters[i] == x && y == 1)
{
letters[i] = letters[i] - 1;
}
}
printf("\n");
y++;
}
x--;
}
printf("... ");
for( int i = 0; i < 26; i++ )
{
printf("%c", alpha[i]);
}
}
However my current code has two problems.
1. I always print out 10 Y-axis points i want to only print out as many Y-axis points as needed, What would be the best way to achieve this?
2. Currently only lower case characters are counted, how can i address this?
Also any notation or better methodology would be much appreciated, Im still trying to learn!
Thanks!
2nd question seems bit easy to me :
2. Currently only lower case characters are counted, how can i address this?
make an structure like this :
typedef struct
{
char c;
int count;
}alpha;
alpha abc[26];
for(i=0 ; i<26 ; i++)
abc[i].count = 0; // Initialization of count for each alphabet
for(i=0;i<26; i++)
abc[i].c = 'a' + i;
In this way you can keep track of each letter with it's count.
To print "histogram" of each alphabet in file you need (11 + 1 + 1) lines
(means at least 13 lines , can be extra lines for separating characters and their bar )
11 lines for 11 times occurrence of alphabet and 1 for + as mentioned and 1 for alphabets itself.
But to print these lines, You need to take care of extra things about the space before the each of the *(histogram symbol you used).
So, loop through the array and print it like, For your 1st question try something like this:
int cnt;
for(cnt = 11 ; c >=0 ; c--)
{
for(i=0; i<26; i++)
{
if(abc[i].count >= cnt && cnt == 11)
{
space = abc[i].c - 'a';
printf("%*c",space,'+'); // setting indentation and printing
}
if(abc[i].count == cnt && cnt != 11)
{
space = abc[i].c - 'a';
printf("%*c",space,'*'); //// setting indentation and printing
}
printf("\n");
} //end of inner for loop
} // end of outer for loop
printf("abcdefghijklmnopqrstuvwxyz\n");
A different data representation would simplify your program.
Use one table to hold all possible one byte characters; the byte val of the char serves as key; # of occurences is val.
Note the use of while ((c = getchar()) != EOF); the idiom for reading input one byte at a time - your getLetters() routine skipped every other char.
The program below handles both upper and lowercase letters; but is restricted to one-byte encodings - it does not properly handle utf8, utf16 etcetera. For more info on text encodings read this article. What isalpha() treats as a letter depends on the current locale, which can by altered by setlocale
#include <stdio.h>
#include <ctype.h>
#include <limits.h>
enum { NROWS = 10 };
void draw_line(int count[], double scale, int level);
void draw(int count[]);
int main() {
int count[UCHAR_MAX+1] = {0};
int c;
while ((c = getchar()) != EOF)
count[c]++;
for (c = 0; c <= UCHAR_MAX; c++)
if (isalpha(c) && count[c] != 0)
printf("%c %d\n", c, count[c]);
draw(count);
return 0;
}
My draw graph version, scales the y values instead of printing '+' for large values. It prints out only as many "y-axis stars" as neeeded by comparing the count to the level of the y-axis.
void draw(int count[]) {
int c, i;
int max = 0;
double scale;
for (c = 0; c <= UCHAR_MAX; c++)
if (isalpha(c) && count[c] > max)
max = count[c];
scale = (max == 0) : 1.0 : (double)max / NROWS;
for (i = NROWS; i > 0; i--)
draw_line(count, scale, i);
for (c = 0; c <= UCHAR_MAX; c++)
if (isalpha(c))
putchar(c);
putchar('\n');
}
void draw_line(int count[], double scale, int level) {
int c;
for (c = 0; c <= UCHAR_MAX; c++) {
if (isalpha(c) && count[c] / scale >= level)
putchar('*');
else if (isalpha(c))
putchar(' ');
}
putchar('\n');
}
An example output of the graph:
$ ./countchars < countchars.c
[..snip..]
*
* *
* *
* * * *
* * * * *
* * * * * * *
* * * * * ** * **
* *** ** * ** * **
* * **** ** * *** ****
* * * * * * * * **** ** ***** ******
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz