How to add comma separated values in string in C - c

How do I add all csv values in the string?
I made a skeleton but should I convert string to integer and use += to add all integers?
#include <stdio.h>
int main(void)
{
int i; // index
int num=0, sum=0; // number
char str[]="123,456,789";
for(i=0; str[i]; i++) {
if (str[i] == ',') { // begin a new number
- ā‘  - // multiple statements are allowed
} else { // a digit
num = ā‘”;
}
}
sum += num;
printf("Sum of all values in CSV[%s] : %d", str, sum);
return 0;
}

There are many many ways to go about this. The preferred is simply to use strtol for its intended purpose and iterate over the string using the endptr parameter to update your position in the string to one after the last digit following a successful conversion.
However, there is good value in learning to iterate over a string with either array indexing (or preferably pointers) to parse what you need from the string. There is nothing too complicated to parse with a pair of pointers inch-worming your way down the string picking out what you need.
Here it appears you want to loop over each character in the string, testing for commas or digits and taking the appropriate action to either add the digit to your number, or add your number to the sum if a comma is encountered. Don't forget you must convert the ASCII value for the character to its integer value before using it in your number.
A simple implementation of what you are attempting could look like the following:
#include <stdio.h>
int main(void)
{
int i,
num=0,
sum=0;
char str[] = "123,456,789";
for (i = 0; str[i]; i++) /* loop over each char */
if (str[i] == ',') { /* begin a new number */
sum += num; /* add number to sum */
num = 0; /* reset number to 0 */
}
else /* add digit to number */
num = num * 10 + (str[i] - '0');
sum += num; /* add final number to sum */
printf ("Sum of all values in CSV[%s] : %d\n", str, sum);
return 0;
}
Example Use/Output
$ ./bin/csvsum
Sum of all values in CSV[123,456,789] : 1368
A strtol Implementation
The reason strtol (or any of the strtoX family) are preferred is due to the error checking they provide for the conversion as well as the built in advancing of the pointer within the string being converted to the next character in the string following the digits converted. (in your case the endptr parameter will either point to a comma or the nul-terminating character in the string after each conversion.
This allows you to simply walk down the string with strtol and a pair of pointers (p and ep -- pointer and end-pointer), converting each set of digits to a number as you go with strtol (p, &ep, base). After each successful conversion, just skip forward with ep until you find the next '+-' or '0-9' that will start the next valid conversion and set p = ep; and repeat. (if you reach the nul-terminating character while advancing ep - you know you are done with the conversions)
A simple implementation would be:
#include <stdio.h>
#include <stdlib.h> /* for strtol */
#include <limits.h> /* for INT_MAX */
#include <errno.h> /* for errno */
#define BASE 10 /* added benefit - strtol will convert from many bases */
int main (void)
{
int sum=0;
long tmp = 0; /* tmp long for strtol conversion */
char str[] = "123,456,789",
*p = str, *ep = NULL; /* pointer and end-pointer */
for (;;) { /* perform conversion until end (or error) */
errno = 0; /* reset errno */
tmp = strtol (p, &ep, BASE); /* perform conversion, update ep */
if (errno) { /* check conversion was valid */
fprintf (stderr, "error: invalid conversion.\n");
return 1;
}
if (tmp < INT_MAX - sum) /* make sure tmp will fit in sum */
sum += (int)tmp; /* add tmp to sum */
else {
fprintf (stderr, "error: sum overflowed.\n");
return 1;
}
/* find the next '+-' or 'digit' or end of string */
while (*ep && *ep != '+' && *ep != '-' && ( *ep < '0' || '9' < *ep))
ep++;
if (!*ep) break; /* if *ep is nul-character, end reached, bail */
p = ep; /* update pointer to end-pointer, repeat */
}
printf ("Sum of all values in CSV[%s] : %d\n", str, sum);
return 0;
}
Look things over and let me know if you have further questions.

Here is a solution with strtol() and strspn() that does not modify the input string:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int sum_csv(const char *str) {
int sum = 0;
for (;;) {
char *p;
int n = strtol(str, &p, 10); /* convert number */
if (p == str) /* stop if no number left */
break;
sum += n; /* accumulate (ignore overflow) */
str = p + strspn(p, ", "); /* skip number and delimiters */
}
return sum;
}
int main(void) {
printf("sum is %d\n", sum_csv("123,465,798");
return 0;
}

First you can trim all white spaces and all.
Secondly as you mentioned there will only be integers separated by commas so you should understand the general way to get an integer.
So what is the idea?
You will continue to form the number unless you see a comma or end of string.
How to form the number?
|ABCD
num
A|BCD A [Here also 10*0+A]
AB|CD A*10+B
ABC|D (A*10+B)*10+C
ABCD| ((A*10+B)*10+C)*10+D = 1000*A+100*B+10*C+1*D
You repetitively multiply the existing number with 10 and then add it.
This way you form the number.
I have avoided giving the answer with functions. There are other options like using builtin functions like strtok etc. You can check them in reference.

You can perform want you want with strtok and strtol functions:
int main(void)
{
/* delimiter: string will be cut on spaces and comma */
char delim[] = " ,";
char *tok;
/* string to parse */
char str[] = "123,465,798";
int sum = 0, num;
/* get first token, warning `str` is modified */
tok = strtok(str, delim);
while (tok)
{
/* convert token to int */
num = strtol(tok, NULL, 0);
/* add it to sum */
sum += num;
/* read next token */
tok = strtok(NULL, delim);
}
printf("sum is %d\n", sum);
return 0;
}

int main() {
int i; // index
int iGroup=0;// groupNumber array
int num=0, sum=0; // number
char str[]="123,456,789";
char strNum[16];
memset(&strNum[0], 0, sizeof(strNum));
for(i=0; str[i]!='\0'; i++) {
if (str[i] == ',' ) { // Get the group number array since the numbers
iGroup=0; //Reset the index of the groupNumber array
num=atoi(strNum); //Convert the array to numbers
memset(&strNum[0], 0, sizeof(strNum)); //Set the groupNumber array to null
sum += num;
} else { // a digit
strNum[iGroup]=str[i]; //Add the character to groupNumber array
iGroup++;
}
}
num=atoi(strNum);
sum += num;
//sum += num;
printf("Sum of all values in CSV[%s] : %d", str, sum);
return 0;
}

Related

C - read a string of numbers

I want to read a string of numbers (only intigers) that I don't know and also I don't know how many of these numbers I will have to read. Each will be separated by whitespace. So waht is the best way to do it?
You don't have to write me a code or something, I just want to know what should I use.
Thank you
You can read character by character. Everytime you find number(character from 48 to 57), add to temporary string. When you have whitespace, try to parse created string. Then empty it. And continue it till the end of the big string.
I think that this might work
int main(){
char name[100];
printf("Insert numbers: ");
fgets(name, 100, stdin);
printf("Your numbers: %s\n", name);
return 0;
}
You have to read in a loop, skipping the blank spaces (see isspace(3)) and in an inner loop, while (isdigit(getchar())) (see isdigit(3))
I'll write some code (if you don't want to be spoiled out, don't read below until you are satisfied with your solution):
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
/* this macro calculates the number of elements of an array.
* you must be carefull to always pass an array (not a pointer)
* to effectively get the number of elements */
#define SIZE(arr) ((sizeof arr) / (sizeof arr[0]))
int main()
{
int n = 0;
int a[100];
/* this has to be an int (not a char) see getchar() manpage */
int last_char = 0;
/* while n < number of elements of array a */
while (n < SIZE(a)) {
/* read the character into last_char and check if it is
* a space, tab or newline */
while (isspace(last_char = getchar()))
continue;
/* last_char is not a space, it can be EOF, a minus sign,
* a digit, or something else (not a number) */
if (last_char == EOF)
break; /* exit the outer loop as we got no more input data */
int neg = (last_char == '-'); /* check for negative number */
if (neg) last_char = getchar(); /* advance */
/* check for digits */
if (isdigit(last_char)) {
/* digits are consecutive chars starting at '0'. We are
* assuming ASCII/ISO-LATIN-1/UTF-8 charset. This doesn't
* work with IBM charsets. */
int last_int = last_char - '0';
while (isdigit(last_char = getchar())) {
last_int *= 10; /* multiply by the numeration base */
last_int += last_char - '0'; /* see above */
}
/* we have a complete number, store it. */
if (n >= SIZE(a)) { /* no more space to store numbers */
fprintf(stderr,
"No space left on array a. MAX size is %d\n",
SIZE(a));
exit(EXIT_FAILURE);
}
if (neg) last_int = -last_int;
a[n++] = last_int;
}
/* next step is necessary, because we can be on a terminal and
* be able to continue reading after an EOF is detected. Above
* check is done after a new read to the input device. */
if (last_char == EOF)
break;
} /* while (n < SIZE(a) */
printf("Number list (%d elements):", n);
int i;
for (i = 0; i < n; i++) {
printf(" %d", a[i]);
}
printf("\n");
exit(EXIT_SUCCESS);
} /* main */

How do I parse a string of numbers into a array of integers?

I have been struggling with this for a while and figured I might as well ask for help instead of banging my head harder into a wall.
So let's say you have the string "10 10 10 4 4 4 9 9 9 2"
and you want to go through it, take out the numbers one by one and add it to an array of integers to use.
I have prototyped A LOT and keep making more work for myself than is necessary. At first I was using strtok() but then people said that was deprecated and it would be easier to use strsep()
How would I go about doing this?
Any help would be greatly appreciated!
My function seems to always return an int array full of zeros. Why is this?
int *parse_line(char *line){
char sNumArray[MAX];
strcpy(sNumArray, line);
char *tokens = NULL;
int *numbers = malloc(sizeof(int) * MAX);
tokens = strtok(sNumArray, " ");
for(int i = 0; ; i++) {
numbers[i] = atoi(tokens);
printf("%d \n", atoi(tokens));
tokens = strtok(NULL, " ");
if (tokens == NULL)
break;
}
return numbers;
}
These are my variables I define in the main and call my function with...
int *skyline;
skyline = parse_line(line);
for (int j = 0; j < 100 ; ++j) {
printf("%d \n", skyline[j]);
}
You have three primary options (1) use strtol in the manner it was intended, using the *endptr parameter to advance the current read position within the string to one past the last digit converted, or (2) pass to sscanf utilizing the "%n" specifier to report the number of characters used in the conversion to int (or whatever type) and using that value to advance the read position in the same manner; or (3) tokenizing the string with strtok and then using strtol (as atoi should not be used as it provides absolutely zero error checking). There really isn't any need to use both strtok and strtol as strtol already provides a way to advance past the digits converted. You are essentially duplicating what has already by done by strtol by using a call to strtok -- but it is a valid way to go.
For instance using strtol you could do something like the following:
#include <stdio.h>
#include <stdlib.h> /* for strtol */
#include <string.h> /* for strncpy */
#include <errno.h> /* for errno */
#define MAXC 1024 /* constant - max chars in line */
int main (void) {
char str[MAXC] = ""; /* str to hold line, initialized all zero */
while (fgets (str, MAXC, stdin)) { /* read each line of input */
char *p = str, /* pointer for strtol */
*endptr = NULL; /* end pointer for strtol */
while (*p) { /* work down str parsing integer or hex values */
long val = strtol (p, &endptr, 0); /* convert from p */
/* validate conversion */
if (p != endptr) { /* were digits converted? */
if (!errno) { /* if errno 0, successful conversion */
char ascii[MAXC] = ""; /* for string converted */
strncpy (ascii, p, endptr - p); /* copy to ascii */
ascii[endptr-p] = 0; /* nul-terminate ascii */
/* test whether string begins "0x" or "0X", output */
if (*p == '0' && (*(p + 1) == 'x' || *(p + 1) == 'X'))
printf ("hex conversion: %-10s %10lu 0x%lx\n",
ascii, val, val);
else
printf ("int conversion: %-10s % ld\n",
ascii, val);
}
p = endptr; /* advance p to 1-past end of converted string */
}
/* find start of next valid number in str, including (+/-) */
for (; *p; p++) {
if ('0' <= *p && *p <= '9') /* positive value */
break; /* explicitly signed value */
if ((*p == '+' || *p == '-') && '0' <= *(p+1) && *(p+1) <= '9')
break;
}
}
}
return 0;
}
Example Use/Output
$ echo "10 10 10 4 4 4 9 9 9 2" | ./bin/fgets_strtol_any
int conversion: 10 10
int conversion: 10 10
int conversion: 10 10
int conversion: 4 4
int conversion: 4 4
int conversion: 4 4
int conversion: 9 9
int conversion: 9 9
int conversion: 9 9
int conversion: 2 2
or converting all the integers in a messy file, e.g.
Example Input File
$ cat dat/10intmess.txt
8572,;a -2213,;--a 6434,;
a- 16330,;a
- The Quick
Brown%3034 Fox
12346Jumps Over
A
4855,;*;Lazy 16985/,;a
Dog.
11250
1495
Example Use/Output
$ ./bin/fgets_strtol_any <dat/10intmess.txt
int conversion: 8572 8572
int conversion: -2213 -2213
int conversion: 6434 6434
int conversion: 16330 16330
int conversion: 3034 3034
int conversion: 12346 12346
int conversion: 4855 4855
int conversion: 16985 16985
int conversion: 11250 11250
int conversion: 1495 1495
Using sscanf
Similarly, you can use sscanf, but be mindful, it doesn't provide the level or degree of error handling -- meaning you can only know that it either successfully converted the text or it failed. No in between, no reporting of overflow or underflow through errno. But still, it along with strtok are other valid means of parsing integers from a line of text, e.g.
#include <stdio.h>
#include <stdlib.h>
#define MAXC 1024
int main (int argc, char **argv) {
char buf[MAXC] = ""; /* buffer to hold MAXC chars at a time */
int nval = 0; /* total number of integers found */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
while (fgets (buf, MAXC, fp)) {
char *p = buf; /* pointer to line */
int val, /* int val parsed */
nchars = 0; /* number of chars read */
/* while chars remain in buf and a valid conversion to int takes place
* output the integer found and update p to point to the start of the
* next digit.
*/
while (*p) {
if (sscanf (p, "%d%n", &val, &nchars) == 1) {
printf (" %d", val);
if (++nval % 10 == 0) /* output 10 int per line */
putchar ('\n');
}
p += nchars; /* move p nchars forward in buf */
/* find next number in buf */
for (; *p; p++) {
if (*p >= '0' && *p <= '9') /* positive value */
break;
if (*p == '-' && *(p+1) >= '0' && *(p+1) <= '9') /* negative */
break;
}
}
}
printf ("\n %d integers found.\n", nval);
if (fp != stdin) fclose (fp); /* close file if not stdin */
return 0;
}
Example Use/Output
$ echo "10 10 10 4 4 4 9 9 9 2" | ./bin/fgets_sscanf_int_any_ex
10 10 10 4 4 4 9 9 9 2
10 integers found.
or with messy input
$ echo "1, 2 buckle my shoe, 3, 4..." | ./bin/fgets_sscanf_int_any_ex
1 2 3 4
4 integers found.
Using strtok would simply be a "front-end" to conversion with strtol shown in the first example (which provides its own way to tokenizing numeric values). You simply loop over your buffer calling strtok with delimiters of " \n" (space newline) and then using strtol to convert the string pointed to. (here you are simply using endptr to validate digits were converted and ignoring its use to advance past the digits converted. Essentially, strtok duplicates what is already done by strtok, but if it makes it easier to understand, and you can live with the duplicate call, it's fine. You could do something like the following.
while (fgets (buf, MAXC, fp)) {
char *p = buf; /* pointer to buf to use with strtok */
/* 1st call using buffer, all remaining calls using NULL */
for (p = strtok (p, " \n"); p; p = strtok (NULL, " \n")) {
errno = 0; /* reset errno */
char *endptr; /* end pointer */
long tmp = strtol (p, &endptr, 0); /* convert using long */
if (p != endptr) { /* validate digits converted */
/* now validate value within range of int */
if (!errno && INT_MIN <= tmp && tmp <= INT_MAX)
/* you have an integer! */
}
else if (tmp == 0)
/* no digits were converted */
}
}
Look things over and let me know if you have further questions.
I think this will do what you want.
#include "stdafx.h"
#include <stdio.h>
#include <iostream>
#include <math.h>
#include <stdlib.h>
using namespace std;
#define MAX 100
int *parse_line(char *line, int *numInts) {
char sNumArray[MAX];
strcpy(sNumArray, line);
int *numbers = (int *) malloc(sizeof(int) * MAX);
char *tokens = strtok(sNumArray, " ");
for (int i = 0; ; i++) {
numbers[i] = atoi(tokens);
tokens = strtok(NULL, " ");
if (tokens == NULL) {
*numInts = i+1;
break;
}
}
return numbers;
}
int main() {
char *line = "10 10 10 4 4 4 9 9 9 2";
int numIntsExtracted = 0;
int *skyline = parse_line(line, &numIntsExtracted);
for (int j = 0; j < numIntsExtracted; ++j) {
printf("%d \n", skyline[j]);
}
return 0;
}
And the output I'm getting after running it.
10
10
10
4
4
4
9
9
9
2
I like to use the function strtol() for this, because if you pass it a pointer, it will return the next point to continue parsing. There are also unsigned versions, e.g.: strtoul(). They are standard since C99. Also strtol() can parse hexadecimal, and handles errors somewhat better than older functions like atoi() (which returns 0 on error).
The important part of the code below is the result from strtol(). When next_number is un-changed after the call, there is no more input (or an error occurred). The variable ptr is used to keep track of where the parsing is up to in the string. It's given to strtol(), which changes next_number to point to the next element, so then ptr jumps forward - assigned to next_number (past the element just parsed), and the process repeats.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *number_str = "10 10 10 4 4 4 9 9 9 2";
char *ptr;
char *next_number;
int numbers[1000];
int number_count = 0;
long num;
next_number = number_str;
do
{
ptr = next_number;
num = strtol(ptr, &next_number, 10);
if (ptr != next_number) // found one
{
numbers[number_count] = (int)num;
printf("Stored %3d into numbers[%d]\n", numbers[number_count], number_count);
number_count += 1;
}
} while(ptr != next_number);
return 0;
}
Just use scanf() to get each number one by one in for or while loop.
for i = 0 to n
scanf(ā€œ%dā€, &num);
Pls refer google or bing search online how it is done with many examples available.

Time Limit When Solving this problem in C [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
Upper Lower
Bibi also wants to challenge Jojo and Lili. She has a string S with N as its length. The string can contain
uppercase and lowercase characters. Then she will do an iteration from the start of the string, if the K-th
character is an uppercase character, then she will change all the characters after it, such that uppercase
character will become lowercase and lowercase character will become uppercase. After the end of the
iteration, she will ask Jojo and Lili what is the string.
Format Input
1.The first line of the input will contain an integer T, the number of test cases.
2.Each test case will contain a string S and an integer N as its length.
Format Output
For each test case, print "Case #X: " (X starts with 1). Then on the same line, print the string after the
iteration.
Constraints
1 <= T <= 10
1 <= N <= 100000
The string will only consist of uppercase and lowercase characters.
This is my solution. But it keeps getting TLE.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(){
int room,len;
scanf("%d",&room);
char words[100000];
for(int i = 0; i<room; i++){
scanf("%s %d",words,&len);
char next[100000];
int j = 0;
printf("Case #%d: ",i+1);
while(j<len){
int k = j+1;
if(isupper(words[j])){
while(k<len){
if(isupper(words[k])){
words[k] = tolower(words[k]);
}else{
words[k] = toupper(words[k]);
}
k++;
}
}
//printf("%c",words[j]);
j++;
}
printf("%s",words);
printf("\n");
}
return 0;
}
Need help for better solution.
I think the TLE comes from nested loops, but I can't figure it out without nested loops.
In the "new algorithm" department - you've implemented the algorithm as stated. However, that means you're spending a lot of time (the majority of the time, I'll guess) looping through the string, changing the case of characters, potentially multiple times. You don't actually need to do this. Keep a counter of the number of uppercase characters you've found, initially set to zero. When you examine a character, check the counter. If the counter is odd (i.e. if (counter & 1)...), reverse the case of the character you're currently looking at (change upper to lower, lower to upper). Having done that, test to see if the character you're currently looking at is uppercase (it may have just changed to that). If so, increment the counter. Then proceed to the next character.
This can be done in-place and in a single pass, without any nested loops.
So your loop over the string looks something like
for (i = 0, counter = 0 ; i < strlen(string) ; ++i)
{
if (counter & 1) /* if counter is odd */
if (isupper(string[i])) /* if character [i] is upper case */
string[i] = tolower(string[i]); /* convert character [i] to lower case */
else
string[i] = toupper(string[i]); /* convert character [i] to upper case */
if(isupper(string[i])) /* if character [i] is now upper case */
counter += 1; /* increment the counter */
}
Best of luck.
You can try this with some pointers magic. Also, try to separate your program into functions, so each part of your code has a clear purpose. Finally, scanf is not a very good solution to get user input: if user enters more characters than expected, it can break your program (or your system if you use Windows). I've just used this scan_str as an example.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
/* Helper function to swap a character case */
char swap_case(char c) {
if(isupper(c))
return tolower(c);
return toupper(c);
}
/* Our iteration test case */
char*test_iterate(char*str) {
char *p, *p0;
/* Don't swap until first upper char is found */
int swap = 0;
/*
* - Initialize both pointers to beginning of string
* - Iterate until a 0 is found (end of string)
* - Each iteration, "advance" pointer by one
*/
for(p0 = p = str; *p != 0; p++) {
/* If is upper, begin to swap case */
if(isupper(*p))
swap = 1;
*p = swap ? swap_case(*p) : *p;
}
/* Return pointer to begining of word */
return p0;
}
/*
* `scanf("%s", &word)` is not good if you are serious and want to avoid memory overflow
*/
char*scan_str() {
/* Lets begin with 10 bytes allocated */
size_t buf_size = 10;
char c, *word = (char*) malloc(buf_size);
int length = 0;
/* Iterate reading characters from `stdin` until ENTER is found */
while( (c = getc(stdin)) != '\n' && c != EOF ) {
/* If we need more than already allocated, allocate more (10 bytes more) */
if((length + 1) >= buf_size) {
buf_size += 10;
word = realloc(word, buf_size);
if(word == NULL)
return "Some weird error.";
}
/* Save read char to our word/buffer */
word[length] = c;
length++;
}
/* Add word ending character */
word[length] = 0;
return word;
}
int main(void) {
int room;
/* Two dimensional array: list of string pointers */
char**tests;
/*
* Use `scanf` to read an integer
* It's still not good enough, as you need this weird `%*c` to discard ENTER inputs
*/
printf("Insert number of tests to do:\n");
scanf("%d%*c", &room);
/* Allocate memory for `tests`: array of pointers to strings */
tests = (char**) malloc(sizeof(char*) * room);
/* Get input from user */
for(int i = 0; i < room; i++) {
printf("Insert test case #%d:\n", i + 1);
tests[i] = scan_str();
}
/* Print results and free each test memory */
for(int i = 0; i < room; i++) {
printf("Case #%d: %s\n", i + 1, test_iterate(tests[i]) );
free(tests[i]);
}
/* Free `tests` array */
free(tests);
return 0;
}

How to find number of occurrences in array of chars in C?

I am trying to enter a word, and get how many times the letters were typed.
Say my input is "hello"
my output would be: h = 1, e = 1 l = 2 etc.
I am very close to getting it right, but I have a small issue with this code:
#include <stdio.h>
#include <string.h>
void find_frequency(char s[], int count[]) {
int c = 0;
while (s[c] != '\0') {
if (s[c] >= 'a' && s[c] <= 'z' )
count[s[c]-'a']++;
c++;
}
}
int main()
{
char string[100];
int c, count[26] = {0};
printf("Input a string\n");
gets(string);
find_frequency(string, count);
printf("Character Count\n");
for (c = 0 ; c < 26 ; c++)
if(count[c] > 0)
printf("%c : %d\n", c + 'a', count[c]);
return 0;
}
This code does half of the job, but not all.
It's output is in alphabetical order. How can i change it to give me an output of just the chararray that is input?
As Ry- suggested in this comment you could iterate back over the original string and use the chars as indices into your frequency table. Something like the following:
int len_string = strlen(string);
for (c=0; c<len_string; c++) {
char ch = string[c];
printf("%c: %d, ", ch, count[ch-'a']);
}
This won't completely match your expected output, since this code will output l: 2 twice, but that raises the question:
What is your expected output when you have a string like abba? a:2, b:2? a:1, b:2, a:1? a: 2, b:2, a:2? It's hard to help when you ask such an ambiguous question.
#include <stdio.h>
#include <string.h>
size_t ASCIIfreq[256];
void CountASCII(void *buff, size_t size)
{
unsigned char *charsptr = buff;
memset(ASCIIfreq, 0, sizeof(ASCIIfreq));
while(size--)
{
ASCIIfreq[*charsptr++]++;
}
}
void print(int printall)
{
for(size_t index = 0; index < 256; index++)
{
if(ASCIIfreq[index] || printall)
{
printf("The %03zu (0x%02zx) ASCII - '%c' has occured in the buffer %zu time%c\n",
index, index, (index > 32 && index < 127) ? (char)index : ' ',
ASCIIfreq[index], ASCIIfreq[index] == 1 ? ' ' : 's');
}
}
}
int main()
{
char teststring[] = "i am trying to enter a word, and get how many times the letters were typed. Say my input is \"hello\" my output would be: h = 1, e = 1 l = 2 etc.I am very close to getting it right, but i have a small issue with this code";
CountASCII(teststring, sizeof(teststring));
print(0);
return 0;
}
It's not clear what you mean by:
How can i change it to give me an output of just the chararray that is input?
Because that's exactly what you're doing in any case: Inputting a char array to the function; which is updated with numbers alphabetically; and later output as is.
So I'm guessing that you want to output the counts in the same order that each char was first encountered?
Solution
This will require a bit more work. You could keep a second array tracking the the order each character is encountered within find_frequency. But then that simple clean function starts doing too much.
So consider rather tweaking how you do the output:
void output_frequency(char s[], int count[]) {
int c = 0;
//loop s for the output
while (s[c] != '\0') {
if (s[c] >= 'a' && s[c] <= 'z' ) {
//found a character, report the count only if not reported before
if (count[s[c]-'a'] > 0) {
printf("%c : %d\n", s[c], count[s[c] - 'a']);
count[s[c]-'a'] = 0; //so you don't report this char again
}
}
c++;
}
}
If you are attempting to get an in-order count instead of a count in alphabetical order, you simply need to coordinate the indexes of your count array with the order of characters in your input buffer. To do that, simply loop over all characters in your input buffer and make a second pass counting the number of times the current character occurs. This will give you an in-order count of the number of times each character occurs, e.g.
#include <stdio.h>
#include <string.h>
#define COUNT 128
#define MAXC 1024
int main (void) {
char buf[MAXC] = ""; /* buffer to hold input */
int count[COUNT] = {0}; /* array holding inorder count */
fputs ("enter string: ", stdout); /* prompt for input */
if (!fgets (buf, MAXC, stdin)) { /* read line into buf & validate */
fputs ("error: EOF, no valid input.\n", stderr);
return 1;
}
/* loop over each character not '\n' */
for (int i = 0; buf[i] && buf[i] != '\n'; i++) {
char *p = buf; /* pointer to buf */
size_t off = 0; /* offset from start of buf */
while ((p = strchr (buf + off, buf[i]))) { /* find char buf[i] */
count[i]++; /* increment corresponding index in count */
off = p - buf + 1; /* offset is one past current char */
}
}
for (int i = 0; count[i]; i++) /* output inorder character count */
printf (i ? ", %c: %d" : "%c: %d", buf[i], count[i]);
putchar ('\n'); /* tidy up with new line */
return 0;
}
(note: strchr is used for convenience to simply find the next occurrence of the current character within the string and then off (offset) is used to start the search with the following character until no other matches in the string are found. You can simply use an additional loop over the characters in the buffer if you like.)
Example Use/Output
$ /bin/charcnt_inorder
enter string: hello
h: 1, e: 1, l: 2, l: 2, o: 1
However, this does recount each character and give the count again if the character is duplicated, (e.g. l: 2, l: 2 for each 'l'). Now it is unclear from:
"my output would be: h = 1, e = 1 l = 2 etc."
what you intended in that regard, but with just a little additional effort, you can use a separate index and a separate array to store the first instance of each character (in say a chars[] array) along with the count of each in your count[] array and preserve your inorder count while eliminating duplicate characters. The changes needed are shown below:
#include <stdio.h>
#include <string.h>
#define COUNT 128
#define MAXC 1024
int main (void) {
char buf[MAXC] = "",
chars[COUNT] = ""; /* array to hold inorder chars */
int count[COUNT] = {0};
size_t cdx = 0; /* add count index 'cdx' */
fputs ("enter string: ", stdout);
if (!fgets (buf, MAXC, stdin)) {
fputs ("error: EOF, no valid input.\n", stderr);
return 1;
}
for (int i = 0; buf[i] && buf[i] != '\n'; i++) {
char *p = buf;
size_t off = 0;
chars[cdx] = buf[i]; /* store in chars array */
if (i) { /* if past 1st char */
int n = i;
while (n--) /* simply check all before */
if (buf[n] == buf[i]) /* if matches current */
goto next; /* bail and get next char */
}
while ((p = strchr (buf + off, buf[i]))) {
count[cdx]++; /* increment count at index */
off = p - buf + 1;
}
cdx++; /* increment count index */
next:; /* goto label to jump to */
}
for (int i = 0; count[i]; i++)
printf (i ? ", %c: %d" : "%c: %d", chars[i], count[i]);
putchar ('\n');
return 0;
}
Example Use/Output
$ /bin/charcnt_inorder2
enter string: hello
h: 1, e: 1, l: 2, o: 1
or
$ ./bin/charcnt_inorder2
enter string: amarillo
a: 2, m: 1, r: 1, i: 1, l: 2, o: 1
Now your 'l' is only reported once with the correct count.
Note, in each example you should do additional validation to insure the entire input fit within your buffer, etc... The count (and chars) array were sized at 128 to cover the entire range of ASCII values. Don't skimp on buffer size. If you explicitly limit your input to UPPERcase or lowercase -- then you can limit your count size to 26, otherwise you need to consider the additional characters and punctuation that will be encountered. The same applies to your input buffer. If you anticipate you max input would be 500 chars, double it (generally to next available power of two, no real requirement for powers of two, but you are likely to see it that way).
Bottom line, I'd rather be 10,000 characters too long that one character too short... leading to Undefined Behavior.
Lastly, as mentioned in my comment never, never, never use gets. It is so insecure it has been removed from the C standard library in C11. Use fgets or POSIX getline instead.
Look things over and let me know if you have further questions.

How to write C program that accepts user input that contain both integers and punctuation characters?

Solution
#include <stdio.h>
#include <string.h>
int main()
{
char value[50];
char *end;
int sum = 0;
long conv;
while(conv != 0 )
{
printf("Enter a measurement and unit(Ex: 4' or 3\";0' or 0\" when done): ");
fgets(value, 50, stdin);
conv = strtol(value, &end, 10);
if(strstr(value, "\'") != NULL)
{
conv = strtol(value, &end, 10);
sum = sum + (conv*12);
}
else if(strstr(value, "\"") != NULL)
{
conv = strtol(value, &end, 10);
sum = sum + conv;
}
}
printf("Total: %d, %s\n", sum, "inches" );
return 0;
}
UPDATE Still having problems with new program..unsure where to go from here. It is accepting numbers and quotes, but it keeps multiplying any number I type in by 12 when it should only do that if I enter a single quote to specify feet.
UPDATE2 Here are the functions for Assembly that we should keep in mind for writing the C program:
void printStr(char *)
Arguments:
edi = address of null-terminated string to print
Returns:
Nothing
void printUInt(unsigned)
Arguments:
edi = Unsigned integer to print
Returns:
Nothing
char getchar()
Arguments:
None
Returns:
eax = the next character
uinsigned readUInt()
Arguments:
None
Returns:
eax = an unsigned int read from stdin.
(eax is 0 on error)
I must write a C program which prompts the user to enter a measurement(number) and unit( ' or ", which represent feet or inches) and then prints out the Total length in inches AFTER the user enters a length of '0' which acts as a sentinel value.
This program is only needed to act as a way for me to then build an Assembly program with a similar structure. The thing is, it must be built around 4 functions that would be called to help perform some of the operations.
So my C program should be built similarly with those functions in mind. Here's what I have:
Here is my program:
UPDATED:
int main()
{
char value[50];
char *end;
int sum = 0;
long conv;
while(conv != 0)
{
printf("Enter a measurement and unit: ");
fgets(value, 50, stdin);
conv = strtol(value, &end, 10);
if(value[1]='\'')
{
sum = sum + (conv*12);
}
if(value[1]='\"')
{
sum = sum + conv;
}
}
printf("Total: %d\n", sum);
return 0;
}
OLD:
int main()
{
int sum = 0;
int value;
char symbol;
while(value != 1)
{
printf("Enter measurement and unit: ");
scanf("%d,%d", &value, &symbol);
if(symbol == "'")
{
sum = sum + value*12;
}
else if(symbol == ''' )
{
sum = sum + value;
}
sum = sum + value;
}
printf("Total: %d", sum);
return 0;
}
I hope I have enough information here for someone to help me even though I know we're missing the complete functions for time being. And I know the IA32 assembly conversion is not my main question and I think I will save that for another if I get stuck, but I hope getting this High-Level language program corrected will get me going in the right direction. Thanks in advance!
Get the character using %c not %d. Change the line into like this.
if ( scanf("%d,%c", &value, &symbol) != 2 )
continue;
While comparing you have to do like this,
if(symbol == '\"')
{
sum = sum + value*12;
}
else if(symbol == '\'' )
{
sum = sum + value;
}
Output after this,
Enter measurement and unit: 2,"
Enter measurement and unit: 3,'
Enter measurement and unit: 1,"
Total: 45
When you think about writing a program that will be translated to assembly, you want to limit yourself to using calls that have a 1-to-1 correlation to the system calls available in assembly. That means leaving the high-level world of buffered input/output and using the unbuffered low-level input/output methods where you are responsible for counting each byte that goes in or out of the program. Even the low-level routines of read and write in C, provide quite a few features that you will have to handle by hand in assembly.
In order to provide a reasonable example of this low-level I/O, I've written a short example to take your input measurements in either feet or inches and keep a running total of the feet and inches entered. The code also converts any inches over 12 into feet accordingly. This example provides a good approximation of the approach you will take in assembly to do the same thing. Take time to understand what each part does, and let me know if you have questions. The lower-level code you write, the longer it becomes to accomplish seemingly simple tasks. Your assembly will probably be 3-times longer.
The program expects input of the form numfeet' or numinches". So to enter 10 feet, enter 10', for 10 inches, enter 10":
#include <stdio.h>
#include <unistd.h>
#define STDINFD 0
#define STDOUTFD 1
#define newline write (STDOUTFD, "\n", 1)
#define MAXS 32
int main (void) {
ssize_t n = 0; /* number of characters read */
size_t i = 0; /* general iteration variable */
size_t digits = 0; /* digit counter */
char buf[MAXS] = {0}; /* buffer to hold input */
char *bp = buf; /* pointer to input buffer */
char length[MAXS] = {0}; /* buffer to hold measurement */
char *p = length; /* pointer to measurement */
char fbuf[MAXS] = {0}; /* buffer to hold feet */
char *fp = fbuf; /* pointer to feet */
char ibuf[MAXS] = {0}; /* buffer to hold inches */
char *ip = ibuf; /* pointer to inches */
unsigned feet = 0; /* total feet entered */
unsigned inches = 0; /* total inches entered */
unsigned num = 0; /* general unsigned value */
unsigned mlt = 1; /* place multiplier value */
unsigned incvt = 0; /* inches to feet conversion */
char unit = 0; /* buffer for ''' or '"' */
char const digit[] = "0123456789"; /* conversion string */
/* input prompt and labels */
char prompt[] = "\n Enter measurement with units [feet' or inches\"]: ";
char nlabel[] = "\n number : ";
char ulabel[] = "\n unit : ";
char flabel[] = "\n feet : ";
char ilabel[] = "\n inches : ";
/* write prompt to stdout */
write (STDOUTFD, prompt, sizeof prompt);
/* read length and unit until [CTRL+D] entered */
while ((n = read (STDINFD, bp, 32)) != 0)
{
/* re-initialize values for each loop */
bp = buf;
p = length;
fp = fbuf;
ip = ibuf;
i = 0;
num = 0;
incvt = 0;
mlt = 1;
unit = 0;
/* parse each character read into buf */
while (bp[i] != '\n')
{
if (bp[i] >= '0' && bp[i] <= '9') /* is a digit */
*p++ = bp[i];
if (bp[i] == 0x27) /* is a ' */
unit = bp[i];
if (bp[i] == '"') /* is a " */
unit = bp[i];
i++;
}
/* null-terminate / decrement length pointer */
*p = 0;
p--;
/* write length and unit to stdout */
write (STDOUTFD, nlabel, sizeof nlabel);
write (STDOUTFD, length, p - length + 1);
write (STDOUTFD, ulabel, sizeof ulabel);
write (STDOUTFD, &unit, sizeof unit);
newline;
/* convert characters in length to number */
for (i = p - length; p >= length; p--)
{
num += (*p - '0') * mlt;
mlt *= 10;
}
/* test unit and add to feet or inches */
if (unit == '"')
inches += num;
if (unit == 0x27)
feet += num;
/* convert inches > 12 to feet */
if (inches > 12)
{
incvt = inches / 12;
inches -= incvt * 12;
feet += incvt;
}
/* write label for total feet to stdout */
write (STDOUTFD, flabel, sizeof flabel);
/* determine number of digits in feet */
i = 1;
digits = 0;
while (feet >= i && (1UL << 32))
{
digits++;
i *= 10;
}
/* convert number to characters in feet buffer */
num = feet;
fp += digits - 1;
while (fp >= fbuf)
{
*fp-- = digit [num % 10];
num /= 10;
}
/* write the number of feet and label for inches to stdout */
write (STDOUTFD, fbuf, digits);
write (STDOUTFD, ilabel, sizeof flabel);
/* determine number of digits in inches */
i = 1;
digits = 0;
while (inches >= i && (1UL << 32))
{
digits++;
i *= 10;
}
/* convert number to characters in inches buffer */
num = inches;
ip += digits - 1;
while (ip >= ibuf)
{
*ip-- = digit [num % 10];
num /= 10;
}
/* write the number of inches and newline to stdout */
write (STDOUTFD, ibuf, digits);
newline;
/* zero all buffers */
for (i = 0; i < MAXS; i++)
buf[i] = length[i] = fbuf[i] = ibuf[i] = 0;
/* prompt for next input ([CTRL+D] to quit) */
write (STDOUTFD, prompt, sizeof prompt);
}
newline;
return 0;
}
Example / Output
$ ./bin/read_measurement
Enter measurement with units [feet' or inches"]: 10"
number : 10
unit : "
feet :
inches : 10
Enter measurement with units [feet' or inches"]: 10'
number : 10
unit : '
feet : 10
inches : 10
Enter measurement with units [feet' or inches"]: 4"
number : 4
unit : "
feet : 11
inches : 2
Enter measurement with units [feet' or inches"]:
Update to your high-level code
If you are going to continue to use the high-level functions, then make use of the fact that end already points to the next character following the number after you call strtol. e.g.:
while (printf ("\nEnter a measurement and unit: ") && fgets (value, 50 - 1, stdin))
{
errno = 0;
conv = strtol (value, &end, 10);
if (errno == 0 && value != end)
{
if (*end == '\'')
sum = sum + (conv*12);
else if (*end == '\"')
sum = sum + conv;
else
printf ("error: no unit following number.\n");
}
else
printf ("error: no value read.\n");
}
I see several bugs in your "updated" code: one on nearly every line.
int main()
Header files missing. (It's much easier for us to help you if you give us a complete program that can be compiled and tested without modification.)
Should be int main(void); empty argument parentheses are poor style.
{
char value[50];
char *end;
int sum = 0;
This is fine.
long conv;
while(conv != 0)
Use of uninitialized variable. I would write a do-while loop instead.
{
printf("Enter a measurement and unit: ");
Unnecessary use of printf (better fputs since no formatting is required).
fgets(value, 50, stdin);
If you have getline, use it.
conv = strtol(value, &end, 10);
It is necessary to set errno to zero manually before any use of the strto* functions, because some errors are only visible that way.
if(value[1]='\'')
Your immediate problem is here. There are three bugs on this line:
You haven't checked whether strtol returned an error.
value[1] is the second character read by fgets, not the character immediately after the number. The character immediately after the number is end[0].
Comparison uses ==, not =; this condition is assigning '\'' to value[1] and then testing whether '\'' is nonzero; since '\'' has to be nonzero, the body of the if-statement always executes, which is why you are seeing it always multiply by 12. This would have been more obvious if you had put spaces around the =. If you had run the compiler with warnings enabled, it would have told you about this mistake.
{
sum = sum + (conv*12);
}
ok
if(value[1]='\"')
Same problems as the earlier if-statement; should be else if.
{
sum = sum + conv;
}
Missing else clause here in which you report an error because the character after the number was neither ' nor ".
Missing check for junk input after the number and unit specifier.
}
printf("Total: %d\n", sum);
return 0;
}
the rest is fine
You probably could also use a primer on how to check whether strtol returned an error. This is a little finicky, because strtol has no special return value that indicates an error; if an error happened, it will either set errno, or not consume any characters. Unfortunately, when an error did not happen, it does not necessarily clear errno, so you have to do it yourself:
errno = 0;
conv = strtol(value, &end, 0);
if (end == value || errno) {
fputs("Invalid number, or no number entered\n", stderr);
continue;
}

Resources