Convert input char array to full integer number in C - arrays

I am trying to create a function that scans the user input and shows the counted integer numbers and add them. For example the user input would be 'room 2301 next to 12 street' the function would count the number 2301 as one, and 12 as two and add them, 2313 which is the sum and returns it. so the return would be count=2, sum= 2313. However, I am having an issue with the logic behind the function. Currently my function takes the numbers separately, eg. 2302 = 2,3,0,2.
Here is my code:
void num_count(char array[]) {
int i = 0;
int count = 0;
int sum = 0;
int tmp[20];
tmp_size = 20;
while (array[i] != '\0') {
if (array[i] >= '0' && array[i] <= '9') {
tmp[i] = (array[i] - '0');
//not sure what to do here
count++;
sum += (array[i] - '0');
}
i++;
}
}
currently I try to put it into a temp array but not really sure what to do next. Any help would be appreciated .

I think you should begin from the end of the array to the beginning.
When you encounter a digit you have to sum this first digit, then iterate the next character and if it is a digit you have to sum digit x10, the next one: digit x100...
When the next character is not a digit, reset the multiplier and count++.
if(isDigit){
sum+= digit*multiplier;
multiplier*=10;
}
else {
multiplier=1;
}
I don't inlcude the count part.

Use the following code snippet to extract the individual words of the string, check if the extracted word is a number, and, if a number, calculate the sum and increase the count.
int i;
int j;
int count;
int sum;
char *chars;
char *pChar;
int len;
int isNum;
for (i=0, count=0, sum=0; i<strlen(array);) {
pChar = strchr(array[i], ' ');
len = pChar - array[i];
chars = malloc(sizeof(char) * (len + 1));
strncpy(chars, array[i], len);
chars[len] = '\0';
for (j =0, isNum = 1; j<len; j++) {
if (!isdigit(chars[j])) {
isNum=0;
break;
}
}
if (isNum) {
count++;
sum += atoi(chars);
}
free(chars);
if (strchr(array[pChar - array + 1] != NULL)
i = (pChar - array) + 1;
else
break;
}

If you only need the sum, you do not have to save it as char in a char array (in your code it is named tmp[]), but you can directly convert it to integer (assuming no overflow will occur).
Every time you detect the first numeric character, you should reset the tmp to zero and continue multiplying by 10 before adding the next numeric value, until you detect a non-numeric character.
edit: I think the function should return the sum. So, you'd better change the function decoration as well (and add a return sum line).
int num_count(char array[]) {
int i = 0;
int sum = 0;
int tmp;
while (array[i] != '\0') {
if (array[i] >= '0' && array[i] <= '9') {
tmp = 0;
while (array[i] >= '0' && array[i] <= '9') {
tmp = tmp * 10 + array[i] - '0';
i++;
}
sum += tmp;
}
else {
i++;
}
}
return sum;
}

Related

Compute the most frequent digit in a string of digits in C

I am trying to compute the most frequent digit in a string of characters, and I need to use pointers but I am not sure how to go about this with pointers.
int most(char* string){
int counter = 0;
int* array =(int*) malloc(sizeof(int)*10);
char* original = string;
while(*original){
counter++;
string++;
//Not sure what to put in this loop
}
}
for example, I want to call the code
char nums[] = "132433423";
printf("%d \n",most(nums));
// 3
The specification for your function is incomplete:
can the string contain non-digit characters?
what should be returned if there are no digits at all?
which value should be returned if there are multiple digits with the same maximum number of occurrences?
should the function return the digit or its numeric value? Your main() function uses the latter, but it is not clear from the text of the question.
The most function receives a pointer to the string. You can write a loop where you handle one character at a time and increment the pointer for the next iteration until you reach the end of the string. You must also decide what to return if the string contains no digits.
Here is a simple example:
int most(const char *s) {
int count[10] = { 0 };
int res, i, max;
while (*s) {
if (*s >= '0' && *s <= '9')
count[*s - '0']++;
s++;
}
res = -1; /* return -1 if no digits */
max = 0;
for (i = 0; i < 10; i++) {
if (count[i] > max)
res = i;
}
return res;
}
If you are restricted from using any array at all, allocating a block of memory seems indeed a good solution:
int most(const char *s) {
int *count = calloc(sizeof(*count), 10);
int res, i, max;
while (*s) {
if (*s >= '0' && *s <= '9')
*(count + *s - '0') += 1;
s++;
}
res = -1; /* return -1 if no digits */
max = 0;
for (i = 0; i < 10; i++) {
if (*(count + i) > max)
res = i;
}
free(count);
return res;
}
The notation *(count + *s - '0') += 1 works this way: count is a pointer to an array of int allocated and initialized to 0 by calloc. *s - '0' is the digit value n of the character pointed to by s, that has been tested to be a digit. count + *s - '0' is a pointer to the n-th entry in the array. *(count + *s - '0') += 1 increments this value by one.
There are ways to do this without memory allocation, with 10 variables and explicit tests for the different digits, but I doubt this be the expected solution.
If you can explain your choices to your teacher, there are 2 ways to use arrays without the [ and ] characters. These are obsolescent features of the C Standard, which most programmers are not familiar with, and which you can ignore unless you are curious:
int most(const char *s) { /* version with C99 digraphs */
int count<:10:> = { 0 };
int res, i, max;
while (*s) {
if (*s >= '0' && *s <= '9')
count<:*s - '0':>++;
s++;
}
res = -1; /* return -1 if no digits */
max = 0;
for (i = 0; i < 10; i++) {
if (count<:i:> > max)
res = i;
}
return res;
}
Or
int most(const char *s) { /* version with old-style trigraphs */
int count??(10??) = { 0 };
int res, i, max;
while (*s) {
if (*s >= '0' && *s <= '9')
count??(*s - '0'??)++;
s++;
}
res = -1; /* return -1 if no digits */
max = 0;
for (i = 0; i < 10; i++) {
if (count??(i??) > max)
res = i;
}
return res;
}
You could first sort the string so that the smaller digit characters appear first in num. You could use qsort() (from stdlib.h) like
int cmpfn(const void *a, const void *b)
{
int x = *(char *)a;
int y = *(char *)b;
return x-y;
}
int main()
{
char nums[] = "132433423";//"111222223333";//
qsort(nums, sizeof(nums)/sizeof(nums[0]) -1, sizeof(nums[0]), cmpfn);
printf("\nAfter sorting: %s", nums);
. . . . . . . . . .
. . . . . . . . . .
}
Declare variables to store the mode (ie, the value that appears most frequently in the data) and the frequency of the mode value.
int mode=-1, modecount=-1, n;
Now find the frequency of each digit character. Since this is a sorted character array, the same value will appear consecutively.
for(char *ptr=nums, *lptr=NULL; *ptr; ptr+=n)
{
lptr = strrchr(ptr, *ptr);
n = lptr - ptr + 1;
if(n>modecount)
{
printf("\n%c", *ptr);
modecount = n;
mode = *ptr;
}
}
printf("\nMode is: %c", mode);
strrchr() (from string.h) will find the last occurrence of a character in a string.
#include<string.h>
int most (char* nums) {
int i, max_index = 0;
int digit_dictionary[10]={0,0,0,0,0,0,0,0,0,0};
for (i=0; i< strlen(nums); i++) {
digit_dictionary[nums[i]-'0'] ++;
}
for (i=1; i<10; i++) {
if (digit_dictionary[i]> digit_dictionary[max_index])
max_index = i;
}
return max_index;
}
I will try to be as elaborate as I can:
You create a dictionary in which each index corresponds to a digit that can occur (0-9). Then, iterate through the string(which is basically an array of characters, and store each digit to its corresponding index in dictionary.
Note: [nums[i]-'0'] is calculated into the index of the dictionary since each char has an integer value (look up ASCII table). The counter at that index is incremented to keep count of number of occurrences of that digit.
After that, go through the dictionary to determine at which position is the digit with most occurrences, and return that digit.
I'm not sure what you mean by "using pointers", but here's a version which doesn't use pointers except for walking the input string:
char most_frequent_character(char *s)
{
int freq[10];
int max_freq;
int max_idx;
int idx;
while(*s)
freq[*s++ - '0']++; /* compute character freqs */
max_idx = 0;
max_freq = freq[0];
for(idx = 1 ; idx < 10 ; ++idx)
if(freq[idx] > max_freq)
{
max_freq = freq[idx];
max_idx = i;
}
return '0' + max_idx;
}
Have fun.
EDIT
To convert the above to "use pointers":
A. Change freq to a pointer-to-int and initialize it using malloc; in addition, initialize the memory pointed to by freq using memset:
int *freq = malloc(sizeof(int) * 10);
memset(freq, 0, sizeof(int)*10);
B. In the "compute character freqs" loop, use pointer references instead of indexing:
while(*s)
{
*(freq + (*s - '0')) = *(freq + (*s - '0')) + 1;
s++;
}
C. Use a pointer ref to set the initial value of max_freq:
max_freq = *freq;
D. In the for loop, use pointer math instead of indexing:
for(idx = 1 ; idx < 10 ; ++idx)
if( *(freq + idx) > max_freq)
{
max_freq = *(freq + idx);
max_idx = i;
}
E. Free the memory allocated earlier before the return statement:
free(freq);
return '0' + max_idx;
Now, sit down and understand why things are done in the way that they are here. For example, why didn't I do the following when computing the character frequencies?
while(*s++)
*(freq + (*s - '0')) = *(freq + (*s - '0')) + 1;
or
while(*s)
*(freq + (*s++ - '0')) = *(freq + (*s++ - '0')) + 1;
Each of the above would save several lines of code - why shouldn't they be used? (The obvious answer is "because they won't work as intended" - but WHY?)
Best of luck.

How do I allocate memory to my char pointer?

My assignment is to allow the user to enter any input and print the occurrences of letters and words, we also have to print out how many one letter, two, three, etc.. letter words are in the string. I have gotten the letter part of my code to work and have revised my word function several times, but still can't get the word finding function to even begin to work. The compiler says the char pointer word is undeclared when it clearly is. Do I have to allocate memory to it and the array of characters?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void findLetters(char *ptr);
void findWords(char *point);
int main()
{
char textStream[100]; //up to 98 characters and '\n\ and '\0'
printf("enter some text\n");
if (fgets(textStream, sizeof (textStream), stdin)) //input up to 99 characters
{
findLetters(textStream);
findWords(textStream);
}
else
{
printf("fgets failed\n");
}
return 0;
}
void findLetters(char *ptr) //find occurences of all letters
{
int upLetters[26];
int loLetters[26];
int i;
int index;
for (i = 0; i < 26; i++) // set array to all zero
{
upLetters[i] = 0;
loLetters[i] = 0;
}
i = 0;
while (ptr[i] != '\0') // loop until prt[i] is '\0'
{
if (ptr[i] >= 'A' && ptr[i] <= 'Z') //stores occurrences of uppercase letters
{
index = ptr[i] - 'A';// subtract 'A' to get index 0-25
upLetters[index]++;//add one
}
if (ptr[i] >= 'a' && ptr[i] <= 'z') //stores occurrences of lowercase letters
{
index = ptr[i] - 'a';//subtract 'a' to get index 0-25
loLetters[index]++;//add one
}
i++;//next character in ptr
}
printf("Number of Occurrences of Uppercase letters\n\n");
for (i = 0; i < 26; i++)//loop through 0 to 25
{
if (upLetters[i] > 0)
{
printf("%c : \t%d\n", (char)(i + 'A'), upLetters[i]);
// add 'A' to go from an index back to a character
}
}
printf("\n");
printf("Number of Occurrences of Lowercase letters\n\n");
for (i = 0; i < 26; i++)
{
if (loLetters[i] > 0)
{
printf("%c : \t%d\n", (char)(i + 'a'), loLetters[i]);
// add 'a' to go back from an index to a character
}
}
printf("\n");
}
void findWords(char *point)
{
int i = 0;
int k = 0;
int count = 0;
int j = 0;
int space = 0;
int c = 0;
char *word[50];
char word1[50][100];
char* delim = "{ } . , ( ) ";
for (i = 0; i< sizeof(point); i++) //counts # of spaces between words
{
if ((point[i] == ' ') || (point[i] == ',') || (point[i] == '.'))
{
space++;
}
}
char *words = strtok(point, delim);
for(;k <= space; k++)
{
word[k] = malloc((words+1) * sizeof(*words));
}
while (words != NULL)
{
printf("%s\n",words);
strcpy(words, word[j++]);
words = strtok(NULL, delim);
}
free(words);
}
This is because you are trying to multiply the pointer position+1 by the size of pointer. Change line 100 to:
word[k] = malloc(strlen(words)+1);
This will solve your compilation problem, but you still have other problems.
You've got a couple of problems in function findWords:
Here,
for (i = 0; i< sizeof(point); i++)
sizeof(point) is the same as sizeof(char*) as point in a char* in the function fincdWords. This is not what you want. Use
for (i = 0; i < strlen(point); i++)
instead. But this might be slow as strlen will be called in every iteration. So I suggest
int len = strlen(point);
for (i = 0; i < len; i++)
The same problem lies here too:
word[k] = malloc((words+1) * sizeof(*words));
It doesn't makes sense what you are trying with (words+1). I think you want
word[k] = malloc( strlen(words) + 1 ); //+1 for the NUL-terminator
You got the arguments all mixed up:
strcpy(words, word[j++]);
You actually wanted
strcpy(word[j++], words);
which copies the contents of words to word[j++].
Here:
free(words);
words was never allocated memory. Since you free a pointer that has not been returned by malloc/calloc/realloc, the code exhibits Undefined Behavior. So, remove that.
You allocated memory for each element of word. So free it using
for(k = 0; k <= space; k++)
{
free(word[k]);
}
Your calculation of the pointer position+1 is wrong. If you want the compilation problem will go away change line 100 to:
word[k] = malloc( 1 + strlen(words));

char into int and calculate sum of int

I want split the following string into alphabet and numbers, then I need to calculate the sum of the numbers. My sample question is a[20]={"abcd123dc2"};
Expected output:
abcddc 8
My code:
int main()
{
char a[20] = {"abcd123dc2"};
int l = 0, m = 0, n = 0, j, cc = 0, ll = 0;
char b[20];
char c[10];
l = strlen(a);
printf("%d", l);
for (j = 0; j < l; j++)
{
if (a[j] == 'a' || a[j] == 'b' || a[j] == 'd' || a[j] == 'c')
{
b[m] = a[j];
m++;
}
}
b[m] = '\0';
for (j = 0; j < l; j++)
{
if (a[j] == '3' || a[j] == '2' || a[j] == '1')
{
c[n] = a[j];
n++;
}
}
ll = strlen(c);
atoi(c);
for (j = 0; j < ll; j++)
{
cc += c[j];
}
printf("%d\n\n", cc);
printf("%s", b);
getch();
return 0;
}
char a[20]={"abd123vf"};
int l=0,m=0,j,cc=0;
char b[20];
l=strlen(a);
for(j=0;j<l;j++)
{
if(a[j]> 47 && a[j] <58){
cc+ = a[j] - '0';
}
else{
b[m]=a[j];
m++;
}
}
b[m]='\0';
printf("%d\n\n",cc);
printf("%s",b);
getch();
return 0;
Edit after the first comment:
Since you have not specifically mentioned a problem, I assume you are looking for a better way of writing this code.
Instead of looping through your string twice, you can do it in a single go.
Instead of checking for individual numbers or letters, you can check if the character is in the range : 48 - 57 [i.e., 0 to 9]
Instead of two if conditions, you can go for an else.
[Note that even the special characters in the original string will be part of your new string in this case]
a[j] - '0' will give the actual number in the string. eg:
if the number is 5, a[j] will be 53;
'0' is 48; 53 - 48 = 5 and that's what you add to your sum
Your code is OK for the most part.
There is one error in computing c. Instead of
cc += c[j]; // The integer value of c[j] when it is `0` is 48, not 0
You need to use
cc += c[j] - '0';
Based on your expected output at the top of the question, your printf lines
printf("%d\n\n",cc);
printf("%s",b);
need to be
printf("%s %d\n",b,cc);
Other
You have an unnecessary call to atoi. Was that just for debugging?
I wouldn't do it this way, the algorithm is actually quite simple. Works for every string.
char a[] = "abcd123dc2";
char b[20];
char c[20];
int i, spotinnumbers = 0, spotincharacters = 0;
for(i = 0 ; i < strlen(a) ; i++)
{
if((a[i] >= 'a' && a[i] <= 'z') || (a[i] >= 'A' && a[i] <= 'Z'))
{
b[spotincharacters] = a[i];
spotincharacters++;
}
else if(a[i] >= '0' && a[i] <= '9')
{
c[spotinnumbers] = a[i];
spotinnumbers++;
}
}
b[spotincharacters] = '\0';
c[spotinnumbers] = '\0';
Some explanation of the code. Basically, it's not splitting, just having another two strings, one of the alphabet in the main string and one of the numbers in it. We use one loop to run on the string and decide whether the character is an alphabet letter or a number and assign it in the right place.
About the sum calculation... As we have the numbers in c:
int total = 0;
for(i = 0 ; i < strlen(c) ; i++)
{
total += c[i]-'0';
}
explanation about this piece of code, in this code, as a string in C is simply an array of characters, in the string we have the characters resembling the numbers but the characters' value in numeric is something called ASCII value. You can look at the ASCII Table and find out that each character has a numeric value and there's an overall of 256 characters (2^8) which is why a character takes one byte (1 byte = 8 bits = 2^8 possibilities for different numbers). '0''s ASCII is 48 and that's how we basically turn a number from a character to its true numeric value. for 0 (48-48 = 0) and for 1 (49-48 = 1) as all number characters in the ASCII table are in a series.
The actual problem in the code isn't just efficiency as there is no need to run in two loops and so, you enter the numeric values of the numbers into C ! which turns them to different characters.

scan n numbers without spaces in C

Suppose n numbers are to be input in a single line without any spaces given the condition that these numbers are subject to the condition that they lie between 1 and 10.
Say n is 6 , then let the input be like "239435"
then if I have an array in which I am storing these numbers then I should get
array[0]=2
array[1]=3
array[2]=9
array[3]=4
array[4]=3
I can get the above result by using array[0]=(input/10^n) and then the next digit
but is there a simpler way to do it?
Just subtract the ASCII code of 0 for each digit and you get the value of it.
char *s = "239435"
int l = strlen(s);
int *array = malloc(sizeof(int)*l);
int i;
for(i = 0; i < l; i++)
array[i] = s[i]-'0';
update
Assuming that 0 is not a valid input and only numbers between 1-10 are allowed:
char *s = "239435"
int l = strlen(s);
int *array = malloc(sizeof(int)*l);
int i = 0;
while(*s != 0)
{
if(!isdigit(*s))
{
// error, the user entered something else
}
int v = array[i] = *s -'0';
// If the digit is '0' it should have been '10' and the previous number
// has to be adjusted, as it would be '1'. The '0' characater is skipped.
if(v == 0)
{
if(i == 0)
{
// Error, first digit was '0'
}
// Check if an input was something like '23407'
if(array[i-1] != 1)
{
// Error, invalid number
}
array[i-1] = 10;
}
else
array[i] = v;
s++;
}
E.g.
int a[6];
printf(">");
scanf("%1d%1d%1d%1d%1d%1d", a,a+1,a+2,a+3,a+4,a+5);
printf("%d,%d,%d,%d,%d,%d\n", a[0],a[1],a[2],a[3],a[4],a[5]);
result:
>239435
2,3,9,4,3,5
You can use a string to take the input and then check each position and extact them and store in an array. You need to check for the numeric value in each location explicitly, as you are accepting the input as a string. For integers taken input as string, there's no gurantee that the input is pure numeric and if it is not, things can go wild.
check this code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char ipstring[64];
int arr[64];
int count, len = 0;
printf("Enter the numbersi[not more than 64 numbers]\n");
scanf("%s", ipstring);
len = strlen(ipstring);
for (count = 0; count < len ; count++)
{
if (('0'<= ipstring[count]) && (ipstring[count] <= '9'))
{
arr[count] = ipstring[count] - '0';
}
else
{
printf("Invalid input detectde in position %d of %s\n", count+1, ipstring );
exit(-1);
}
}
//display
for (count = 0; count < len ; count++)
{
printf("arr[%d] = %d\n", count, arr[count]);
}
return 0;
}

C code to convert hex to int

I am writing this code to convert a hex entry into its integer equivalent. So A would be 10 and B would be 11 etc. This code acts weirdly, in that it seg. faults at random locations and including an extra newline character at times will get it to work. I am trying to debug it, just so I can understand what I am doing wrong here. Can anyone take a look and help me here ? Thanks a lot for your time.
/* Fixed working code for anyone interested */
#include <stdio.h>
#include <stdlib.h>
unsigned int hextoint(const char temp[])
{
int i;
int answer = 0;
int dec;
char hexchar[] = "aAbBcCdDeEfF" ;
for ( i=0; temp[i] != '\0'; i++ )
{
if ( temp[i] == '\0')
{
return ;
}
if (temp[i] == '0' || temp[i] == 'x' || temp[i] == 'X' )
{
printf("0");
answer = temp[i];
}
// compare each temp[i] with all contents in hexchar[]
int j;
int a = temp[i];
for ( j=0; hexchar[j] != '\0'; j++)
{
if ( temp[i] == hexchar[j] )
{
answer *= 16;
answer = answer + 10 + (j/2);
// printf("%d\n",answer );
break;
}
}
}
return answer;
}
main()
{
char *test[] =
{ "bad",
"aabbdd"
"0100",
"0x1",
"0XA",
"0X0C0BE",
"abcdef",
"123456",
"0x123456",
"deadbeef",
"zog_c"
};
int answer=0;
// Calculate the number of char's.
int numberOfChars;
numberOfChars = sizeof test /sizeof test[0];
printf("main():Number of chars = %d\n",numberOfChars);
int i;
// Go through each character and convert Hex to Integers.
for ( i = 0; i<numberOfChars;i++)
{
// Need to take the first char and then go through it and convert
it.
answer = hextoint(test[i]);
printf("%d\n",answer );
}
}
Let's take a look.
unsigned int hextoint(const char temp[])
{
int i;
int answer = 0;
char hexchar[] = "aAbBcCdDeEfF" ;
for ( i=0; temp[i] != '\0'; i++ )
{
printf("In here");
printf("%c\t",temp[i] );
}
return answer;
}
This doesn't seem to even try to do any conversion. It should always return 0, since answer is never assigned any other value. Normally, you'd do something like:
for (i=0; input[i] != '\0'; i++) {
answer *= 16;
answer += digit_value(input[i]);
}
return answer;
Where digit_value (obviously enough) returns the value of an individual digit. One way to do this is:
int digit_value(char input) {
input = tolower(input);
if (input >= '0' && input <= '9')
return input - '0';
if (input >= 'a' && input <= 'f')
return input - 'a' + 10;
return -1; // signal error.
}
Then, looking at main:
main()
{
Depending on the "implicit int" rule is generally poor practice, at least IMO. It's much better to specify the return type.
// Calculate the number of char's.
int numberOfChars;
numberOfChars = sizeof test /sizeof test[0];
This actually calculates the number of strings, not the number of chars.
for ( i = 0; i<=numberOfChars;i++)
Valid subscripts run from 0 through the number of items - 1, so this attempts to read past the end of the array (giving undefined behavior).
This'll work for any number within the unsigned int range, the nice thing is it does not use any other library functions so it is great for micro-controllers where space is tight.
unsigned int hexToInt(const char *hex)
{
unsigned int result = 0;
while (*hex)
{
if (*hex > 47 && *hex < 58)
result += (*hex - 48);
else if (*hex > 64 && *hex < 71)
result += (*hex - 55);
else if (*hex > 96 && *hex < 103)
result += (*hex - 87);
if (*++hex)
result <<= 4;
}
return result;
}
The problem is with calculating numberOfChars part. sizeof test is actually the size of the pointer, not the total length of all characters in your array, so the number returned in your code would be 1, which makes the for loop go to the second index of test (test[1]) which does not have a \0 at the end. Try using strlen for calculating numberOfChars.
This may not me the most optimal method, but it should work without problem.
unsigned int hex_to_int(const char* hex) {
unsigned int result = 0;
size_t len = strlen(hex);
for (size_t i = 0; i < len; ++i) {
char cur_char = tolower(hex[len - i - 1]);
// direct return if encounter any non-hex character.
if (!(isdigit(cur_char) && (cur_char >= 'a' && cur_char <= 'f'));)
return result;
unsigned int char_val = (isdigit(cur_char) ? cur_char - '0' : 10 + cur_char - 'a');
result += round(pow(16, i)) * char_val;
}
return result;
}

Resources