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 */
Related
Hi so im trying to make a program that asks for numbers until a letter is typed in C.This is what I have
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(void){
long siz = 10;
float *biglist = malloc(sizeof(float)* siz);
int n, sum = 0;
while ((n = getchar() )!= "d"){
scanf("%d",n);
sum = sum + n;
}
printf("The sum is : %d",sum);
}
While you can do character-oriented input with getchar() and look for some special character to break the loop, that probably isn't the best way to go. Instead when you are reading user-input, you want to use line-oriented input functions to ensure you consume a complete line of input at a time. This ensures there are no offending characters left unread in stdin that will mess up your next input. Now while that is mitigated by reading a character at a time -- the logic you will need to employ to handle all tests and conversions reinvents the wheel.
Instead, if you read a line at a time, you can allow the user to enter as many numbers as they like (one-per-line, up to the limit of your allocation) and then simply press Enter alone on an empty line to stop input. The standard approach is to read a line of input into a buffer (character array) and then parse the needed information from the buffer using sscanf() or if more error detection and reporting is warranted, using strtol(), strtof(), strtod(), etc..
When reading a line at a time, simply provide a sufficiently sized buffer to handle the longest anticipated line (and the cat stepping on the keyboard). If you are on an embedded device, just reduce the buffer size accordingly. To size the buffer (or anything else needing a fixed size), #define a constant or use a global enum for the same purpose, e.g.
#define MAXF 1000 /* if you need a constant, define one (or more) */
#define MAXC 1024
....
char line[MAXC] = "";
float *ma = malloc (MAXF * sizeof *ma), /* or float ma[MAXF] = {0}; */
Now you simply read input checking that the number of inputs fit in your array and checking that '\n' alone wasn't entered, e.g.
puts ("enter one float per-line, [Enter] alone when done");
/* while ma not full, and line read and not empty line */
while (nfloat < MAXF && fgets (line, MAXC, stdin) && *line != '\n') {
For converting the input to float, simply use sscanf() to parse a float from the buffer line validating that a successful conversion took place before incrementing your sum and counter, e.g.
/* if valid conversion to float */
if (sscanf (line, "%f", &ma[nfloat]) == 1) {
sum += ma[nfloat]; /* sum float */
nfloat += 1; /* increment counter */
}
Putting it altogether, you could do:
#include <stdio.h>
#include <stdlib.h>
#define MAXF 1000 /* if you need a constant, define one (or more) */
#define MAXC 1024
int main (void) {
char line[MAXC] = "";
float *ma = malloc (MAXF * sizeof *ma), /* or float ma[MAXF] = {0}; */
sum = 0;
size_t nfloat = 0;
if (ma == NULL) {
perror ("malloc-ma");
return 1;
}
puts ("enter one float per-line, [Enter] alone when done");
/* while ma not full, and line read and not empty line */
while (nfloat < MAXF && fgets (line, MAXC, stdin) && *line != '\n') {
/* if valid conversion to float */
if (sscanf (line, "%f", &ma[nfloat]) == 1) {
sum += ma[nfloat]; /* sum float */
nfloat += 1; /* increment counter */
}
}
printf ("The sum is : %f\n", sum);
free (ma); /* don't forget to free what you allocate */
}
(note: the memory allocated is freed. While this will happen automatically on program exit, you won't always allocate in main(). Failure to free the memory you allocate in that case will lead to a memory-leak if the ability to free the memory is lost)
Example Use/Output
./bin/sumfloats
enter one float per-line, [Enter] alone when done
10.1
10.3
10.3
10.3
The sum is : 41.000000
If you want to output all stored floats, then simply add an output loop before you output the sum, e.g.
for (size_t i = 0; i < nfloat; i++)
printf (i ? " %.1f" : "%.1f", ma[i]);
printf ("\nThe sum is : %.2f\n", sum);
free (ma); /* don't forget to free what you allocate */
}
In that case, you would output each float that is part of sum with precision to 1 digit and the sum with a precision of 2, e.g.
./bin/sumfloats
enter one float per-line, [Enter] alone when done
10.1
10.3
10.3
10.3
10.1 10.3 10.3 10.3
The sum is : 41.00
This is a slight variation on what you were attempting, but this approach will save you a lot of grief (and potential logic errors). Look things over and let me know if you have further questions.
Your getchar() call won't function as you imagine it would.
To begin with, "x" is a string literal, what you actually wanted is, 'x', a single character.
Your malloc() call is correct but you never seem to use the allocated memory and you never call free().
Checking the return value of scanf() would be an easy to exit if anything but a floating point is entered. You can also use fgets() with sscanf(), since scanf() is prone to arithmetic overflow.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
size_t i = 0;
size_t tam = 1000;
float *ma = malloc(sizeof(float) * tam);
float chr, sum = 0;
if (ma == NULL) /* check that malloc succeded */
{
fprintf(stderr, "Allocation failed\n");
exit(EXIT_FAILURE);
}
while ((scanf("%f", &chr) == 1) && i < tam) /* check for overflow and scanf return value */
{
sum = sum + chr;
ma[i++] = chr;
}
/* if you are planning on receiving input again you have to reset/clear the input buffer */
printf("The sum is : %.1f", sum);
free(ma);
return 0;
}
EDIT: If you want to resize the array, you need to use realloc(),
while ((scanf("%f", &chr) == 1)) /* check scanf return value */
{
if (i >= tam)
{
float *tmp = realloc(ma, (tam + 100) * sizeof(float)); /* resize by 100 or desired size, dont forget to add the previous size */
if (tmp == NULL)
{
fprintf(stderr,"Re - Allocation failed\n");
free(ma);
exit(EXIT_FAILURE);
}
ma = tmp;
tam += 100; /* increase the new size */
}
sum = sum + chr;
ma[i++] = chr;
}
So I am trying to write a program that takes a sentence and prints it out from the third word. Ex one two three four should print out three four.
Now this code works but I have no idea why as the logic under the else statement make it seem like it should not.
Would be thankful if someone could explain why it works like this.
Here is the code:
#include <stdio.h>
#include <string.h>
#define SIZE 100
int main(void) {
char arr[SIZE];
char *point;
char again = 'n';
do {
int count = 0;
for (int i = 0; i < SIZE; i++) {
arr[i] = '\0';
}
printf("Enter a sentence:");
gets(arr);
for (int i = 0; i < SIZE; i++) {
if (arr[i] == ' ') {
count++;
}
}
if (count < 2) {
printf("The sentence is to short!\n");
} else {
count = 1; //shouldn't this be count = 0?
for (int i = 0; i < SIZE; i++) {
if (arr[i] == ' ') {
count++;
}
if (count == 2) {
point = &arr[i + 2]; //shouldn't this be [i+1]?
}
}
printf("%s\n", point);
}
printf("Do you want to try again? (y/n)");
scanf("%c", &again);
while (getchar() != '\n');
} while (again == 'y' || again == 'Y');
return 0;
}
Your code has multiple problems:
You should never use gets(). This function has been removed from the C Standard because it cannot be given the maximum number of characters to write to the destination buffer, so any sufficiently long line from the input stream will cause undefined behavior. This is a classic security flaw. Use fgets() instead.
The loop while (getchar() != '\n'); will cause an infinite loop if there is no newline before the end of file, which will happen if you redirect input an empty file. You should also check for EOF:
while ((c = getchar()) != EOF && c != '\n')
continue;
There is no need to initialize the destination array, but you should check if the input operation succeeded, by comparing the return value of fgets() to NULL.
When iterating through the array to count spaces, you should stop at the null terminator. The contents of the array beyond the null terminator is indeterminate after the input operation, even if you initialized it prior to the call.
The code to skip the words is cumbersome and not easy to validate. Indeed point = &arr[i+2]; should be point = &arr[i+1].
words might be separated by more than one space, and initial spaces should be ignored.
Here is a corrected version using string functions strspn and strcspn to skip blanks and non-blanks:
#include <stdio.h>
#include <string.h>
#define SIZE 100
#define WS " \t\n\r\v\f" /* white space characters */
int main(void) {
char arr[SIZE];
char *p;
for (;;) {
printf("Enter a sentence:");
if (fgets(arr, sizeof arr, stdin) == NULL)
break;
p = arr;
p += strspn(p, WS); /* skip initial spaces */
p += strcspn(p, WS); /* skip first word */
p += strspn(p, WS); /* skip spaces */
p += strcspn(p, WS); /* skip second word */
p += strspn(p, WS); /* skip spaces */
if (*p == '\0') {
printf("The sentence is too short!\n");
} else {
printf("%s", p);
}
printf("Do you want to try again? (y/n)");
if (fgets(arr, sizeof arr, stdin) == NULL)
break;
if (*arr != 'y' && *arr != 'Y')
break;
}
return 0;
}
Another simple way to handle the word count is to walk-a-pointer down your string in a state loop keeping track of whether you are in a word (if so increase word count), otherwise you are not in a word and just keep walking down the buffer (i.e. iterating over each char) until you find the next word (or end of string).
The logic is simple, after filling your buffer, and setting a pointer to it, e.g.
#define MAXC 1024 /* buffer size (don't skimp) */
#define NWORD 3 /* output beginning with NWORD word */
...
char buf[MAXC] = "", /* buffer to hold line */
*p = buf; /* pointer to walk down buffer */
int n = 0, /* word counter */
in = 0; /* flag - in a word */
Just loop checking each character with isspace() and handle setting your in flag to either 1 (in word) or 0 (in space before or between words) incrementing your counter each time you go in a new word, and exiting the loop when your count reaches 3, e.g.
for (; *p; p++) { /* loop over each char */
if (!in && !isspace(*p)) { /* if not in word and not space */
in = 1, n++; /* set in flag, increment words */
if (n == NWORD) /* if 3rd word, break */
break;
}
else if (isspace(*p)) /* if space */
in = 0; /* unset in flag */
}
Putting it altogether in a short example, you could do something similar to the following which takes input until the Enter key is pressed alone on an empty line, and outputting each sentence entered beginning with the third-word, or displaying the error "too few words." if a sentence with less that three words is entered, e.g.
#include <stdio.h>
#include <ctype.h>
#define MAXC 1024 /* buffer size (don't skimp) */
#define NWORD 3 /* output beginning with NWORD word */
int main (void) {
for (;;) { /* loop continually until empy-line */
char buf[MAXC] = "", /* buffer to hold line */
*p = buf; /* pointer to walk down buffer */
int n = 0, /* word counter */
in = 0; /* flag - in a word */
fputs ("\nenter sentence: ", stdout); /* prompt */
if (!fgets (buf, MAXC, stdin) || *buf == '\n') { /* read line */
puts ("all done!");
break;
}
for (; *p; p++) { /* loop over each char */
if (!in && !isspace(*p)) { /* if not in word and not space */
in = 1, n++; /* set in flag, increment words */
if (n == NWORD) /* if 3rd word, break */
break;
}
else if (isspace(*p)) /* if space */
in = 0; /* unset in flag */
}
if (n == NWORD) /* if 3 or more words */
fputs (p, stdout);
else /* other wise handle error */
fputs ("too few words.\n", stderr);
}
return 0;
}
Example Use/Output
$ ./bin/thirdword
enter sentence: one two three four five
three four five
enter sentence: one two
too few words.
enter sentence: one two three
three
enter sentence:
all done!
Look things over and let me know if you have further questions.
count = 1; //shouldn't this be count = 0? and point = &arr[i + 2]; //shouldn't this be [i+1]?
The following answers both questions.
count count count count
0 1 2 3
one two three four
i+0 i+1 i+2 i+3
point = &arr[i + 2]; along with printf("%s\n", point); says that print all characters from address of arr[i + 2] till seeing \0 character
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;
}
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 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;
}