I want to store a group of arrays containing 2 numbers in an array. But I only want 2 numbers to be stored when 5 followed by a comma and another number is entered. Essentially, what I want my program to do is read from this array of arrays and perform tasks accordingly. So if the user enters 2, I want to store (2,0) in one space of my array and move on to ask my user for the second number. But if the user types 5,10 I want the program to store (5,10) in that same array. Then my program could filter which array has only one value and which has 2 and do different tasks accordingly. My assignment requires us to not ask 2 numbers for each array which would have made it easier.
This is what I have so far and I know I'm wrong I just don't know where to go from here:
int main(void)
{
int size = 0;
int input;
int factor;
int mdArrays[100][2];
for (size_t i = 0; i < 100; i++)
{
size = i;
scanf("%d,%d", &input, &factor);
if (input != 5 && input != 9)
{
factor = 0;
for (size_t j =0 ; j< 2; j++)
{
mdArrays[i] = input;
mdArrays[j] = factor;
}
}
else if (input == 9)
{
break;
}
else
{
for(int j = 0; j< 2; j++)
{
mdArrays[i] = input;
mdArrays[j] = factor;
}
}
}
for (size_t i =0; i < size; i++)
{
for(size_t j = 0; j < 2; j++)
{
printf("%d,%d", mdArrays[i[j]]);
}
}
}
There were a few issues.
size is one too short (it should be i + 1).
It may be possible to handle 5 vs 5,23 using scanf. But, I prefer to use fgets and strtol and check the delimiter (e.g. whether it's , or not).
The if/else ladder logic can be simplified if we make the first test against input == 9 to stop the loop.
According to your code, you want to force a factor of zero if input != 5. That doesn't make much sense to me, but I've kept that logic [for now].
That may not be what you want/need, but it was my best interpretation of your code. The main purpose is to differentiate how many numbers are on a given line. So, adjust the rest as needed.
I think the way you're storing/displaying the array is incorrect. I believe you want to store input into mdArrays[i][0] and factor into mdArrays[i][1]. Using j makes no sense to me.
As I mentioned [in my top comments], the printf in the final loop is invalid.
Note that the code is cleaner if we don't hardwire the dimensions with a literal 100 in multiple places (e.g. once in the myArrays declaration and again in the outer for loop). Better to use (e.g.) #define MAXCOUNT 100 and replace 100 elsewhere with MAXCOUNT (see below).
I created three versions. One that is annotated with original and fixed code. Another that removes the original code. And, a third that organizes the data using a struct.
Here's the refactored code. I've bracketed your/old code [vs. my/new code] with:
#if 0
// old code
#else
// new code
#endif
I added a debug printf. Anyway, here's the code with some annotations:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main(void)
{
int size = 0;
int input;
int factor;
int mdArrays[100][2];
for (size_t i = 0; i < 100; i++) {
#if 0
size = i;
scanf("%d,%d",&input,&factor);
#else
// get line
char buf[100];
char *cp = fgets(buf,sizeof(buf),stdin);
if (cp == NULL)
break;
// strip newline -- only needed for debug print
cp = strchr(buf,'\n');
if (cp != NULL)
*cp = 0;
// decode first number
input = strtol(buf,&cp,10);
// decode second number if it exists -- otherwise, use a sentinel
if (*cp == ',')
factor = strtol(cp + 1,&cp,10);
else
factor = -1;
printf("DEBUG: buf='%s' input=%d factor=%d\n",buf,input,factor);
#endif
// stop input if we see the end marker
if (input == 9)
break;
// remember number of array elements
size = i + 1;
// only use a non-zero factor if input is _not_ 5
if (input != 5) {
factor = 0;
#if 0
for (size_t j = 0; j < 2; j++) {
mdArrays[i] = input;
mdArrays[j] = factor;
}
continue;
#endif
}
#if 0
for (int j = 0; j < 2; j++) {
mdArrays[i] = input;
mdArrays[j] = factor;
}
#else
mdArrays[i][0] = input;
mdArrays[i][1] = factor;
#endif
}
for (size_t i = 0; i < size; i++) {
#if 0
for (size_t j = 0; j < 2; j++) {
printf("%d,%d",mdArrays[i[j]]);
}
#else
printf("%d,%d\n",mdArrays[i][0],mdArrays[i][1]);
#endif
}
return 0;
}
Here's the sample input I used to test:
5,3
7,6
8,9
5,37
5
9,23
Here's the program output:
DEBUG: buf='5,3' input=5 factor=3
DEBUG: buf='7,6' input=7 factor=6
DEBUG: buf='8,9' input=8 factor=9
DEBUG: buf='5,37' input=5 factor=37
DEBUG: buf='5' input=5 factor=-1
DEBUG: buf='9,23' input=9 factor=23
5,3
7,0
8,0
5,37
5,-1
Here's a slightly cleaned up version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXCOUNT 100
int
main(void)
{
int size = 0;
int input;
int factor;
int mdArrays[MAXCOUNT][2];
for (size_t i = 0; i < MAXCOUNT; i++) {
// get line
char buf[100];
char *cp = fgets(buf,sizeof(buf),stdin);
if (cp == NULL)
break;
// strip newline -- only needed for debug print
#ifdef DEBUG
cp = strchr(buf,'\n');
if (cp != NULL)
*cp = 0;
#endif
// decode first number
input = strtol(buf,&cp,10);
// decode second number if it exists -- otherwise, use a sentinel
if (*cp == ',')
factor = strtol(cp + 1,&cp,10);
else
factor = -1;
#ifdef DEBUG
printf("DEBUG: buf='%s' input=%d factor=%d\n",buf,input,factor);
#endif
// stop input if we see the end marker
if (input == 9)
break;
// remember number of array elements
size = i + 1;
// only use a non-zero factor if input is _not_ 5
if (input != 5)
factor = 0;
mdArrays[i][0] = input;
mdArrays[i][1] = factor;
}
for (size_t i = 0; i < size; i++)
printf("%d,%d\n",mdArrays[i][0],mdArrays[i][1]);
return 0;
}
You might benefit from using a struct [YMMV], so here's a version that keeps things organized that way:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXCOUNT 100
typedef struct {
int input;
int factor;
} data_t;
int
main(void)
{
int size = 0;
data_t mdArrays[MAXCOUNT];
data_t *data;
for (size_t i = 0; i < MAXCOUNT; i++) {
// get line
char buf[100];
char *cp = fgets(buf,sizeof(buf),stdin);
if (cp == NULL)
break;
// strip newline -- only needed for debug print
#ifdef DEBUG
cp = strchr(buf,'\n');
if (cp != NULL)
*cp = 0;
#endif
data = &mdArrays[i];
// decode first number
data->input = strtol(buf,&cp,10);
// decode second number if it exists -- otherwise, use a sentinel
if (*cp == ',')
data->factor = strtol(cp + 1,&cp,10);
else
data->factor = -1;
#ifdef DEBUG
printf("DEBUG: buf='%s' input=%d factor=%d\n",buf,input,factor);
#endif
// stop input if we see the end marker
if (data->input == 9)
break;
// remember number of array elements
size = i + 1;
// only use a non-zero factor if input is _not_ 5
if (data->input != 5)
data->factor = 0;
}
for (size_t i = 0; i < size; i++) {
data = &mdArrays[i];
printf("%d,%d\n",data->input,data->factor);
}
return 0;
}
Read a line of user input with fgets() and then parse it to see if it is one number, two comma separated numbers or something else.
I recommend using `"%n" to detect when and how scanning finished.
int get_numbers(int *input, int *factor) {
char buf[80];
if (fgets(buf, sizeof buf, stdin)) {
int n = 0;
sscanf(buf, "%d %n", input, &n);
if (n > 0 && buf[n] == '\0') return 1;
n = 0;
sscanf(buf, "%d ,%d %n", input, factor, &n);
if (n > 0 && buf[n] == '\0') return 2;
return 0; // Invalid input
}
return EOF; // No input
}
Usage
// scanf("%d,%d", &input, &factor);
switch (get_numbers(&input, &factor)) {
case 2: printf("%d %d\n", input, factor); break;
case 1: printf("%d\n", input); break;
case 0: printf("Invalid input\n"); break;
case EOF: printf("No input\n"); break;
}
Related
I have written a C program that takes multiple inputs in the following format: rounds -> rows -> col -> array initial values
I have no issue with the following input: 2 2 2 0 0 0 0
but once put into the other format which looks like this
2
2 2
0 0
0 0
I get a segmentation fault, which I'm not sure why. I feel like I have newlines accounted for. Here is a snippet of my code where I think the error is happening:
int counter = 1;
char *num;
char *str;
long nums;
char line[BUFFER];
fgets (line, BUFFER, stdin);
num = strtok(line, " "); //getting first input that is separated by a space
int rounds = atoi(num); //changes input into a number
num = strtok(NULL, " ");
int row = atoi(num);
num = strtok(NULL, " ");
int col = atoi(num);
int grid[row][col];
for (int i = 0; i < row && !stop; i++){
for (int j = 0; j < col && !stop; j++){
num = strtok(NULL, " \n");
if (num == NULL){ //if the next character after whitespace is null/eof
printf("Invalid input 1");
stop = true;
}else{
nums = strtol(num, &str, 10);
if (*str != '\0' && *str != '\n'){
printf("Invalid input\n");
return 1;
}
int curr = nums;
grid[i][j] = curr;
}
}
}
EDIT: I realize the problem here now, but how would I distinguish if the input is put in the format of a single line vs if the input were on multiple lines so I could use fgets?
If one doesn't care about whitespace, one could completely decouple the input from the parsing. In this modified code, number takes a Buffer, and calls next_int; if this fails, (it will the first time because the buffer is empty,) the line buffer is refilled by calling next_line until it gets at least one number. In this way, it's kind of a singleton producer-consumer pattern.
#include <stdlib.h> /* EXIT malloc free strtol */
#include <stdio.h> /* printf fgets perror */
#include <assert.h> /* assert */
#include <errno.h> /* errno */
#include <string.h> /* strlen */
#include <limits.h> /* INT LONG */
#include <ctype.h> /* isspace */
/** Returns true if `line` was filled up, at most to `size` from `stdin`, thus
this limits the input we can get from `stdin` on top of `fgets`, (embedded
NULs don't work.) If false, `errno` will be set. */
static int next_line(char *line, const size_t size) {
assert(line && size > 2);
if(!fgets(line, size, stdin)) {
if(!ferror(stdin)) fprintf(stderr, "Not enough numbers.\n");
if(!errno) errno = EDOM; /* This is an error in this application. */
return 0;
}
if(line[0] == '\0' || line[strlen(line) - 1] != '\n')
return errno = ERANGE, 0; /* Line too long. */
return 1;
}
/** If EOF, line contained no non-whitespace characters, otherwise, if true,
`*input_ptr` is a whitespace and then number in the range of
`[MIN_INT, MAX_INT]`; it gets moved ahead that amount and `*output_ptr`
contains the number. If false, `errno` will be set. */
static int next_int(char **const input_ptr, int *const output_ptr) {
long l;
assert(input_ptr && output_ptr);
/* We could skip this, but then `errno` would possibly be set. */
while(isspace(**input_ptr)) (*input_ptr)++;
if(**input_ptr == '\0') return EOF;
/* Perform the conversion to `int` using a `long`. */
errno = 0;
l = strtol(*input_ptr, input_ptr, 0);
if((l == 0 || l == LONG_MAX || l == LONG_MIN) && errno) return 0;
if(l > INT_MAX || l < INT_MIN) return errno = ERANGE, 0;
*output_ptr = (int)l;
return 1;
}
/* `sizeof str` is the maximum line. */
struct Buffer { char str[256], *line; };
/** A true return means that we filled the buffer `in` as needed to get an
input `int` which is stored in `no`. Otherwise, `errno`. */
static int number(struct Buffer *const in, int *const no) {
int success;
assert(in && in->line >= in->str && in->line <= in->str + sizeof in->str);
while((success = next_int(&in->line, no)) == EOF) {
if(!next_line(in->str, sizeof in->str)) return 0;
in->line = in->str;
}
return success;
}
int main(void) {
int success = EXIT_FAILURE;
int row, col, *array = 0, i, j;
size_t n = 0, n_max;
struct Buffer in = { "", 0 };
in.line = in.str; /* Complete the `struct Buffer` contract. */
if(!number(&in, &row) || !number(&in, &col)) goto catch;
if(row <= 0 || col <= 0
|| (size_t)row > (size_t)-1 / col
|| (size_t)row * col > (size_t)-1 / sizeof *array)
{ errno = ERANGE; goto catch; } /* Overflow data types. */
n_max = row * col;
if(!(array = malloc(sizeof *array * n_max))) goto catch;
for(n = 0; n < n_max; n++) if(!number(&in, array + n)) goto catch;
for(j = 0; j < col; j++) {
for(i = 0; i < row; i++) {
printf("%s%4d", i ? ", " : "", array[j * row + i]);
}
fputc('\n', stdout);
}
success = EXIT_SUCCESS;
goto finally;
catch:
perror("array");
finally:
free(array);
return success;
}
Also changed,
strtol is used instead of atoi, which is equivalent, but it updates the pointer, has more error reporting, and can handle octal and hex.
C99 varible-length arrays are going to cause stack overflow if one makes them too big. In C17, they are optional. The code above uses malloc instead.
I got a problem of completing the code below.
#include <stdio.h>
void triR(void)
{
int size, repeat;
scanf("%d %d", &size, &repeat);
printf("Hello world\n");
// ...
// Complete this function
// ...
printf("Bye world\n");
}
Example of function excution
The above three are the input values.
I think The first is the minimum size of the number (I do not know why it does not work if I do not enter 1), the middle is the maximum size of the number, and the last is the number of iterations of the input value.
After looking at the example, I created the following code
#include <stdio.h>
#include <stdlib.h>
void triR(void)
{
int size, repeat;
int num;
scanf("%d %d", &size, &repeat);
printf("Hello world\n");
for (int b = 0; b < size; ++b) //b = horizontal line, a = number
{
for (int a = 0; a <= b; ++a)
{
for (num = 1; num <= a; ++num) - failed sentences
{
printf("%d", num);
}
}
printf("\n");
}
for (int k = size; k > 0 ; --k) //k = horizontal line, i = number
{
for (int i = 1; i < k; ++i)
{
{
printf("*"); -Sentences that were successfully run using *
}
}
printf("n");
}
// for (int c =o; ) - sentences tried to make about repeating output value
printf("Bye world\n");
return 0;
}
I know my code looks a lot strange.
I didn't have the confidence to make that code in numbers, so I tried to make it * and convert it.
It succeeded in running by *, but it continues to fail in the part to execute by number.
There is no one to ask for help, but I am afraid that I will not be able to solve it even if I am alone in the weekend. I can not even convert numbers far repeated outputs. I would really appreciate it even if you could give me a hint.
The above code I created(Failed)
Code with *
I'd like to say that even though I managed an implementation, it is definitely neither efficient nor practical. I had to restrict your size variable to digits, as I used ASCII to convert the numbers into characters and couldn't use the itoa() function, since it's not standard.
#include <stdio.h>
#include <stdlib.h>
void triR(void) {
int size, repeat;
scanf("%d %d", &size,&repeat);
printf("Hello world\n");
// string size of n^2+2n-1
char* print_string = malloc((size*size+2*size-1)*sizeof(char));
unsigned int number = 1;
unsigned int incrementer = 1;
while (number < size) {
for (int i = 0; i < number; i++) {
*(print_string+i+incrementer-1) = 48+number;
}
incrementer+=number;
number++;
*(print_string+incrementer-1) = '\n';
incrementer++;
}
while (number > 0) {
for (int i = 0; i < number; i++) {
*(print_string+i+incrementer-1) = 48+number;
}
incrementer+=number;
number--;
*(print_string+incrementer-1) = '\n';
incrementer++;
}
for (int i = 0; i < repeat; i++) {
printf("%s\n", print_string);
}
printf("Bye world\n");
free(print_string);
}
I allocated a char* with the size of size^2+2size-1, as this is the size required for the newline and number characters.
The variables number and incrementer are unsigned and start at 1 as they don't need to go below 1.
I put two while loops with similar code blocks in them:
while (number < size) {
for (int i = 0; i < number; i++) {
*(print_string+i+incrementer-1) = 48+number;
}
incrementer+=number;
number++;
*(print_string+incrementer-1) = '\n';
incrementer++;
}
while (number > 0) {
for (int i = 0; i < number; i++) {
*(print_string+i+incrementer-1) = 48+number;
}
incrementer+=number;
number--;
*(print_string+incrementer-1) = '\n';
incrementer++;
}
The first loop goes up to the size and inserts the characters into the char* in their positions. When the number is done, it increments the incrementer and adds the newline character.
The second loop goes down in number, doing the same things but this time decrementing the number variable. These two variables start at 1, as that's the start of the "pyramid".
*(print_string+i+incrementer-1) = 48+number;
There is a restriction here, in that if you exceed the number 9 your output will print whatever the ASCII representation of 58 is, so if you want to go above 9, you need to change that.
The for loop just prints the final string "repeat" times as wanted. The newline in the printf() function is not necessary, as the final string contains a newline character at the end, I left it in though. The downside of this implementation is that you're using a char* rather than some other sophisticated method.
Dont forget to free the char* when you're done, and don't forget to add user input error-checking.
#include <stdio.h>
#include <stdlib.h>
void clear(FILE *stream)
{
int ch; // read characters from stream till EOF or a newline is reached:
while ((ch = fgetc(stream)) != EOF && ch != '\n');
}
int main(void)
{
int min, max, count;
while (scanf("%d %d %d", &min, &max, &count) != 3 || // repeat till all 3 fields read successfully and
!min || !max || !count || min > max) { // only accept positive numbers as input
fputs("Input error!\n\n", stderr); // and make sure that the max is greater than the min
clear(stdin); // remove everything from stdin before attempting another read for values
}
puts("Hello world\n");
for (int i = 0; i < count; ++i) { // output the triangle count times
for (int row = min; row <= max; ++row) { // count row from min to max
for (int n = min; n <= row; ++n) // print row (row-min) times
printf("%d ", row);
putchar('\n'); // add a newline after every row
}
for (int row = max - 1; row >= min; --row) { // count from max-1 to min
for (int n = min; n <= row; ++n) // same as above: print row (row-min) times
printf("%d ", row);
putchar('\n'); // add a newline after every row
}
putchar('\n'); // add a newline between repetitions
}
puts("Bye world\n");
}
I am self teaching C programming.
I am trying to count number of int present in given string which are separated by space.
exp:
input str = "1 2 11 84384 0 212"
output should be: 1, 2, 11, 84384, 0, 212
total int = 6
When I try. It gives me all the digits as output which make sense since I am not using a right approach here.
I know in python I can use str.split (" ") function which can do my job very quickly.
But I want to try something similar in C. Trying to create my own split method.
#include <stdio.h>
#include <string.h>
void count_get_ints(const char *data) {
int buf[10000];
int cnt = 0, j=0;
for (int i=0; i<strlen(data); i++) {
if (isspace(data[i] == false)
buf[j] = data[i]-'0';
j++;
}
printf("%d", j);
}
// when I check the buffer it includes all the digits of the numbers.
// i.e for my example.
// buf = {1,2,1,1,8,4,3,8,4,0,2,1,2}
// I want buf to be following
// buf = {1,2,11,84384,0,212}
I know this is not a right approach to solve this problem. One way to keep track of prev and dynamically create a memory using number of non space digits encountered.
But I am not sure if that approach helps.
You want to build your number incrementally until you hit a space, then put that into the array. You can do this by multiplying by 10 then adding the next digit each time.
void count_get_ints(const char *data) {
int buf[10000];
int j = 0;
int current_number = 0;
// Move this outside the loop to eliminate recalculating the length each time
int total_length = strlen(data);
for (int i=0; i <= total_length; i++) {
// Go up to 1 character past the length so you
// capture the last number as well
if (i == total_length || isspace(data[i])) {
// Save the number, and reset it
buf[j++] = current_number;
current_number = 0;
}
else {
current_number *= 10;
current_number += data[i] - '0';
}
}
}
I think strtok will provide a cleaner solution, unless you really want to iterate over every char in the string. It has been a while since I did C, so please excuse any errors in the code below, hopefully it will give you the right idea.
#include <stdio.h>
#include <stdlib.h>
int main() {
char str[19] = "1 2 11 84384 0 212";
const char s[2] = " ";
char *token;
int total;
total = 0;
token = strtok(str, s);
while (token != NULL) {
printf("%s\n", token);
total += atoi(token);
token = strtok(NULL, s);
}
printf("%d\n", total);
return 0;
}
You can check the ascii value of each character by doing c-'0'. If it's between [0,9], then it's an integer. By having a state variable, when you're inside an integer by checking if a given character is a number of space, you can keep track of the count by ignoring white space. Plus you don't need a buffer, what happens if data is larger than 10,000, and you write pass the end of the buffer?, undefined behavior will happen. This solution doesn't require a buffer.
Edit, the solution now prints the integers that are in the string
void count_get_ints(const char *data) {
int count = 0;
int state = 0;
int start = 0;
int end = 0;
for(int i = 0; i<strlen(data); i++){
int ascii = data[i]-'0';
if(ascii >= 0 && ascii <= 9){
if(state == 0){
start = i;
}
state = 1;
}else{
//Detected a whitespace
if(state == 1){
count++;
state = 0;
end = i;
//Print the integer from the start to end spot in data
for(int j = start; j<end; j++){
printf("%c",data[j]);
}
printf(" ");
}
}
}
//Check end
if(state == 1){
count++;
for(int j = start; j<strlen(data); j++){
printf("%c",data[j]);
}
printf(" ");
}
printf("Number of integers %d\n",count);
}
I believe the standard way of doing this would be using sscanf using the %n format specifier to keep track of how much of the string is read.
You can start with a large array to read into -
int array[100];
Then you can keep reading integers from the string till you can't read anymore or you are done reading 100.
int total = 0;
int cont = 0;
int ret = 1;
while(ret == 1 && total < 100) {
ret = sscanf(input, "%d%n", &array[total++], &cont);
input += cont;
}
total--;
printf("Total read = %d\n", total);
and array contains all the numbers read.
Here is the DEMO
Example using strtol
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <errno.h>
#include <ctype.h>
int count_get_ints(int output[], int output_size, const char *input) {
const char *p = input;
int cnt;
for(cnt = 0; cnt < output_size && *p; ++cnt){
char *endp;
long n;
errno = 0;
n = strtol(p, &endp, 10);
if(errno == 0 && (isspace((unsigned char)*endp) || !*endp) && INT_MIN <= n && n <= INT_MAX){
output[cnt] = n;
while(isspace((unsigned char)*endp))
++endp;//skip spaces
p = endp;//next parse point
} else {
fprintf(stderr, "invalid input '%s' in %s\n", p, __func__);
break;
}
}
return cnt;
}
int main(void) {
const char *input = "1 2 11 84384 0 212";
int data[10000];
int n = sizeof(data)/sizeof(*data);//number of elements of data
n = count_get_ints(data, n, input);
for(int i = 0; i < n; ++i){
if(i)
printf(", ");
printf("%d", data[i]);
}
puts("");
}
Assuming you don't have any non-numbers in your string, you can just count the number of spaces + 1 to find the number of integers in the string like so in this pseudo code:
for(i = 0; i < length of string; i++) {
if (string x[i] == " ") {
Add y to the list of strings
string y = "";
counter++;
}
string y += string x[i]
}
numberOfIntegers = counter + 1;
Also, this reads the data between the white spaces. Keep in mind this is pseudo code, so the syntax is different.
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;
}
This is a K&R exercise (1-13)...
"Write a program to print a histogram
of the length of words in its input.
It is easy to draw the histogram with
bars horizontal; a vertical
orientation is more challenging."
The section was about arrays, and to be honest, I'm not sure I fully understood it. Everything up to this point was fairly easy to grasp, this was not.
Anyway I'm trying to do a histogram with horizontal bars first. Once I got that down I'll try vertical, but right now I'm not even sure where to begin with the easy version. (I slept on it, woke up, and still couldn't get it.)
I drew an example of what the program would output:
----------------------------------------------------------------
001|XX
002|XXXX
003|X
004|XXXXXXXXXX
005|XXXXXXXXXXXXXXXXXXXXXXXXX
006|XXXX
007|X
008|
009|XXXXXXXXX
010|XXX
>10|XXXX
----------------------------------------------------------------
And tried to break it (the program) down in sections. This is what I came up with:
PRINT TOP BORDER
PRINT CATEGORY, PRINT X EACH TIME CONDITION IS TRUE, PRINT NEWLINE,
REPEAT.
PRINT BOTTOM BORDER
But the more I think about it the less I think that's how it would work (because getchar() goes through one character at a time, and it wouldn't be able to go back up to put a X in the right category.) Or...
... I'm just really confused as to how I would solve this problem. Here's as far as I've been able to get code wise:
#include <stdio.h>
#define MAXWORDLENGTH 10
// print a histogram of the length of words in input. horizontal bar version
int main(void)
{
int c;
while ((c = getchar()) != EOF) {
}
return 0;
}
Could someone help enlighten me? Not necessarily with the code, maybe just pseudo code, or with some "words from the wise" as to what I need to do, or think, or something. This has just been a really big stone in the road and I'd like to get past it :/.
(I'll check back in 30 minutes)
I loved the pseudo-code! Some good thinking there, but you're still not ordering your program right.
As you said yourself, you can't read the text, go back and print an X in a particular row. If we establish that it can't be done, then there's no choice but to know all the values of the histogram beforehand.
So you should think your program as having two parts (and you'll make this kind of division in practically every program you write): first, a part that will make calculations; and then a part that will output them in a certain format (the histogram).
This tip should get you started! If you need further help, comment below.
I suggest you simplify the problem by solving it for the case of one word per line, so you can use fgets. Here's how to "eat up" lines that are too long.
Then, as often, the central data structure is the key to solving the problem. The data structure you need is an array used as frequency table:
int freq[11];
In freq[1], store the number of words/lines of length 1, in freq[2] those of length 2, etc., and in freq[0] those of length >10. You don't need to store the words since the rest of the program only needs their length. Writing out the histogram should be easy now.
I hope this isn't too much of a spoiler.
The code below prints a horizontal histogram using only the basic toolkit provided by the book so far:
#include<stdio.h>
/* Prints a horizontal histogram of the lengths of words */
#define MAX_WORDS 100
#define IN 1
#define OUT 0
main()
{
int c, length, wordn, i, j, state, lengths[MAX_WORDS];
wordn = length = 0;
state = OUT;
for (i = 0; i < MAX_WORDS; ++i) lengths[i] = 0;
while ((c = getchar()) != EOF && wordn < MAX_WORDS)
{
if (c == ' ' || c == '\t' || c == '\n')
state = OUT;
else if (wordn == 0)
{
state = IN;
++wordn;
++length;
}
else if (state == IN)
++length;
else if (state == OUT)
{
lengths[wordn] = length;
++wordn;
length = 1;
state = IN;
}
}
lengths[wordn] = length;
for (i = 1; i <= wordn; ++i)
{
printf("%3d: ",i);
for (j = 0; j < lengths[i]; j++)
putchar('-');
putchar('\n');
}
}
#include<stdio.h>
#define RESET 0
#define ON 1
main()
{
int i,wnum=0,c,wc[50];
int count=0,state;
state=RESET;
for(i=0;i<50;++i)
wc[i]=0;
/*Populating the array with character counts of the typed words*/
while((c=getchar())!=EOF)
{
if(c=='\n'||c=='\t'||c==' '||c=='"')
{
if(state!=RESET)
state=RESET;
}
else if((c>=65&&c<=90)||(c>=97&&c<=122))
{
if(state==RESET)
{
count=RESET;
++wnum;
state=ON;
}
++count;
wc[wnum-1]=count;
}
}
c=RESET;
/*Finding the character count of the longest word*/
for(i=0;i<wnum;++i)
{
if(c<wc[i])
c=wc[i];
}
/*Printing the Histogram Finally*/
for(i=c;i>0;--i)
{
for(count=0;count<wnum;++count)
{
if(wc[count]-i<0)
printf(" ");
else printf("x ");
}
printf("\n");
}
}
VERTICAL ORIENTATION: Using only the tools we learned so far in the book. And you can change the array size, wc[50]. I kept the code valid for 50 words.
Horizontal orientation should be quite simpler. I didn't try it though.
To histogram the word lengths, you are going to need to know the word lengths.
How do you define a word?
How can you measure the length of a word? Can you do it one character at a time as you read the stream, or should you buffer the input an use strtok or something similar?
You will need to accumulate data on how many occurrences of each length occur.
How will you store this data?
You will need to output the results in a pleasing form. This is fiddly but not hard.
I will link the answer below but since you asked for details the key seems to be this
Use an ARRAY of lengths i.e have an array with each element initialised to zero assume MAX wordlength to be about 30...
*have a flag while in the word and increment a counter every time a whitespace is NOT encountered
*once out of the word flag is set to "out" and the corresponding word length index item in the array is incremented i.e if word length counter is w_ctr use
array[w_ctr]++
*use the array as a table of reference for each line in a loop to print each line in the histogram so you can use the array and will now be able to determine weather the 'X' in the histogram is to be inserted or not
EDIT: sorry i didn't read the question right but the idea is simpler for Vertical histograms and the same thing can be used.
after the last step just print the horizontal histogram until counter exceeds current wordlength being printed
for(ctr=0;ctr<array[current_wordlength];ctr++)
printf('X');
End
the original is here http://users.powernet.co.uk/eton/kandr2/krx113.html
CLC-wiki is also a place see the comments for details.
//This is for horizontal histogram.
//It works for any number of lines of words where total words <= MAX
#include <stdio.h>
#define MAX 100 //Change MAX to any value.But dont give words more than MAX.
void main()
{
int w, nwords[MAX] = {0}, i = 0; //nwords is an array for storing length of each word.Length of all words initialized to 0.
while ((w = getchar()) != EOF)
{
if (w == ' ' || w == '\t' || w == '\n')
++i; //if space or tab or newline is encountered, then index of array is advanced indicating new word
else
++nwords[i]; //increment the count of number of characters in each word
} //After this step,we will have array with each word length.
for (i = 0; i < MAX; i++) //iterating through array
{
printf("\n");
for (; nwords[i] > 0; nwords[i]--)
printf("$"); //if length of word > 0 , print $ and decrement the length.This is in loop.
if (nwords[i+1] == 0) //as MAX is 100, to avoid printing blank new lines in histogram,we check the length of next word.
break; //If it is 0, then break the loop
printf("\n"); //After each word bar in histogram, new line.
}
printf("\n");
} //main
I've been also studying K&R book. An good approach is to use a int array for storing word frequencies. The array index is the word length, and the array values are the frequencies.
For example:
int histogram[15]; // declares an int array of size 15
// it is very important to initialize the array
for (int i = 0; i <= 15; ++i) {
histogram[i] = 0;
}
histogram[4] = 7; // this means that you found 7 words of length 4
Given that now you have a data structure for storing your word length frequencies, you can use the same reasoning of Word Counting example found in the book to populate the histogram array. It is very important that you manage to find the right spot for word length tracking (and resetting it) and histogram update.
You can create a function display_histogram for displaying the histogram afterwards.
Here's a code example:
#include<stdio.h>
#define MAX_WORD_LENGTH 15
#define IS_WORD_SEPARATOR_CHAR(c) (c == '\n' || c == ' ' || c == '\t')
#define IN 1
#define OUT 0
/* WARNING: There is no check for MAX_WORD_LENGTH */
void display_horizontal_histogram(int[]);
void display_vertical_histogram(int[]);
void display_histogram(int[], char);
void display_histogram(int histogram[], char type) {
if (type == 'h') {
display_horizontal_histogram(histogram);
} else if (type = 'v') {
display_vertical_histogram(histogram);
}
}
void display_horizontal_histogram(int histogram[]) {
printf("\n");
//ignoring 0 length words (i = 1)
for (int i = 1; i <= MAX_WORD_LENGTH; ++i) {
printf("%2d: ", i);
for (int j = 0; j < histogram[i]; ++j) {
printf("*");
}
printf("\n");
}
printf("\n\n");
}
void display_vertical_histogram(int histogram[]) {
int i, j, max = 0;
// ignoring 0 length words (i = 1)
for (i = 1; i <= MAX_WORD_LENGTH; ++i) {
if (histogram[i] > max) {
max = histogram[i];
}
}
for (i = 1; i <= max; ++i) {
for (j = 1; j <= MAX_WORD_LENGTH; ++j) {
if (histogram[j] >= max - i + 1) {
printf(" * ");
} else {
printf(" ");
}
}
printf("\n");
}
for (i = 1; i <= MAX_WORD_LENGTH; ++i) {
printf(" %2d ", i);
}
printf("\n\n");
}
int main()
{
int c, state, word_length;
int histogram[MAX_WORD_LENGTH + 1];
for (int i = 0; i <= MAX_WORD_LENGTH; ++i) {
histogram[i] = 0;
}
word_length = 0;
state = OUT;
while ((c = getchar()) != EOF) {
if (IS_WORD_SEPARATOR_CHAR(c)) {
state = OUT;
if (word_length != 0) {
histogram[0]++;
}
histogram[word_length]++;
word_length = 0;
} else {
++word_length;
if (state == OUT) {
state = IN;
}
}
}
if (word_length > 0) {
histogram[word_length]++;
}
display_histogram(histogram, 'h');
display_histogram(histogram, 'v');
}
Here's an input/output sample:
kaldklasjdksla klsad lask dlsk aklsa lkas adç kdlaç kd dklask las kçlasd kas kla sd saçd sak dasças sad sajçldlsak dklaa slkdals kkçl askd lsak lçsakç lsak lsak laskjl sa jkskjd aslld jslkjsak dalk sdlk jsalk askl jdsj dslk salkoihdioa slk sahoi hdaklshd alsh lcklakldjsalkd salk j sdklald jskal dsakldaksl daslk
1: *
2: ***
3: ******
4: ***************
5: **********
6: ****
7: ****
8: ***
9:
10: *
11: **
12:
13:
14: **
15:
*
*
*
*
*
* *
* *
* *
* *
* * *
* * *
* * * * *
* * * * * * *
* * * * * * * * *
* * * * * * * * * * *
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
You should separate your 2 problems in functions, like:
void gethist(char *s, int *hist, int len)
{ /* words here breaks on spaces (' ') */
char *t;
for( t=strtok(s," ");t;t=strtok(0," ") )
if(*t)
hist[ strlen(t)>len-1?len-1:strlen(t)-1 ]++;
}
void outhist(int *hist, int len)
{
int i;
for( i=1; i<=len; ++i )
{
char *s = calloc(1,5+hist[i-1]);
sprintf(s,"%03d|", i);
memset( s+4, 'X', hist[i-1]);
puts(s);
free(s);
}
}
then its easy in your main:
int main(void)
{
int c, hist[11] = {};
char *s = calloc(1,1);
while ((c = getchar()) != EOF) {
s = realloc( s, 2+strlen(s) );
s[ strlen(s)+1 ] = 0;
s[ strlen(s) ] = c;
}
gethist(s,hist,11); free(s);
outhist(hist,11);
return 0;
}
The vertical histogram can be printed one line at a time, by going through the array of word lengths and decreasing the word length at each iteration. A # is printed if the word length is still above zero, and a space is printed when it reaches 0. The newline is printed after each iteration.
If lengths[i] holds the number of characters for word i, and wordn is the total number of words, then the following will print the vertical histogram:
#define YES 1
#define NO 0
more_lines = YES;
while (more_lines)
{
more_lines = NO;
for (i = 1; i <= wordn; ++i)
{
if (lengths[i] > 0 )
{
more_lines = YES;
printf("#\t");
--lengths[i];
}
else
printf(" \t");
}
putchar('\n');
}
The complete code is below:
#include<stdio.h>
/* Prints a histogram of the lenghts of words */
#define MAX_WORDS 100
#define IN 1
#define OUT 0
#define YES 1
#define NO 0
main()
{
int c, length, wordn, i, j, state, more_lines, lengths[MAX_WORDS];
wordn = length = 0;
state = OUT;
for (i = 0; i < MAX_WORDS; ++i) lengths[i] = 0;
while ((c = getchar()) != EOF && wordn < MAX_WORDS)
{
if (c == ' ' || c == '\t' || c == '\n')
state = OUT;
else if (wordn == 0)
{
state = IN;
++wordn;
++length;
}
else if (state == IN)
++length;
else if (state == OUT)
{
lengths[wordn] = length;
++wordn;
length = 1;
state = IN;
}
}
lengths[wordn] = length;
/* Print histogram header */
for (i = 1; i <= wordn; ++i)
printf ("%d\t", i);
putchar('\n');
more_lines = YES;
while (more_lines)
{
more_lines = NO;
for (i = 1; i <= wordn; ++i)
{
if (lengths[i] > 0 )
{
more_lines = YES;
printf("#\t");
--lengths[i];
}
else
printf(" \t");
}
putchar('\n');
}
}
Although the exercise is based on Arrays, I tried to write it using the basic while loop and an if statement. I am not really good with Arrays as of now, so thought of trying this out. I have not tested it for bugs though, but it seems to be working fine for most inputs.
#include<stdio.h>
main() {
long int c;
while((c=getchar())!=EOF) {
if(c!=' '&&c!='\n'&&c!='\t') {
putchar("*");
}
if(c==' '||c=='\n'||c=='\t') {
putchar('\n');
}
}
return 0;
}
Please note that this is a very basic piece of code to print it horizontally, just for the basic understanding of the structure.
// Histogram to print the length of words in its input
#include <stdio.h>
main()
{
int wordcount[10],c,token=0;
int word=0, count =0;
for (int i=0; i<10; i++)
{
wordcount[i]=0;
}
while((c=getchar())!=EOF)
{
if(c== ' ' || c == '\n' || c== '\t')
{
// add the length of word in the appropriate array number
switch(word)
{
case 1:
++wordcount[0];break;
case 2:
++wordcount[1];break;
case 3:
++wordcount[2];break;
case 4:
++wordcount[3];break;
case 5:
++wordcount[4];break;
case 6:
++wordcount[5];break;
case 7:
++wordcount[6];break;
case 8:
++wordcount[7];break;
case 9:
++wordcount[8];break;
case 10:
++wordcount[9];break;
}
word =0;
}
else if (c != ' ' || c != '\n' || c!= '\t')
{
word++;
}
}
for (int j=0; j<10; j++)
{
if(wordcount[j]==0)
{
printf("- ");
}
for (int k=0;k<wordcount[j];k++)
printf("X", wordcount[j]);
printf("\n");
}
}
Here is the example of simple vertical Histogram
#include <stdio.h>
int main()
{
int c, i, j, max;
int ndigit[10];
for (i = 0; i < 10; i++)
ndigit[i] = 0;
while ((c = getchar()) != EOF)
if (c >= '0' && c <= '9')
++ndigit[c-'0'];
max = ndigit[0];
for (i = 1; i < 10; ++i) /* for Y-axis */
if (max < ndigit[i])
max = ndigit[i];
printf("--------------------------------------------------\n");
for (i = max; i > 0; --i) {
printf("%.3d|", i);
for (j = 0; j < 10; ++j)
(ndigit[j] >= i) ? printf(" X ") : printf(" ");
printf("\n");
}
printf(" ");
for (i = 0; i < 10; ++i) /* for X-axis */
printf("%3d", i);
printf("\n--------------------------------------------------\n");
return 0;
}
#include <stdio.h>
#include <string.h>
int main()
{
//hold length of string
unsigned long length;
// Holds the name input by user upto 50 characters
char name[50];
//iterator for generating dash for bar chart
int i = 0;
//iterator for generating dash for bar chart
int j = 0;
//take user name input
printf("input your name [without spaces and < 50 characters] : ");
scanf("%s", &name[0]);
//find the length of string
length = strlen(name);
printf("length of your name is %lu \n", length);
//generate dashes for bar chart
while (i < length)
{
printf("--");
++i;
}
printf("| \n");
// fill the bar chart with []
while (j < length)
{
printf("[]");
++j;
}
printf("| \n");
//generate dashes for bar chart
while (length > 0)
{
printf("--");
--length;
}
printf("| \n");
}
input your name [without spaces and < 50 characters] : ThisIsAtestRun
length of your name is 14
----------------------------|
[][][][][][][][][][][][][][]|
----------------------------|
I've tried to implement the latter part of the question (i.e. Displaying the histogram in a vertical manner) and have managed to get most of it done. In the code below, The maximum number of words accepted are 20 and the maximum word length is 10. Also, apologies for not getting the best graphical representation of a typical histogram but the logic to display vertical bars is completely accurate!
Here's my code,
#define MAXWORDS 20
#define MAXLENGTH 10
int c, nlength = 0, i, nword = 0, j;
int length_words[20]= {0};
while((c = getchar()) != EOF && nword <= MAXWORDS)
{
if(c != ' ' && c != '\t' && c != '\n')
++nlength;
else
{
if(nlength != 0){
length_words[nword] = nlength;
++nword;
/* for(i = 0; i < nlength; i++)
printf("O");
printf("\n");*/
printf("Word number: %d has length: %d\n", nword - 1, nlength);
}
nlength = 0;
}
}
// Displaying the Histogram
for(i = MAXLENGTH; i > 0; i--)
{
for(j = 0; j < nword; j++)
{
if(i > length_words[j])
printf(" ");
else
printf(" O ");
}
printf("\n");
}
Feel free to run this and let me know in case of any discrepancy or loopholes!
#include <stdio.h>
int main(void)
{
int i, ii, state, c, largest, highest;
int A[100];
for(i = 0; i < 100; ++i)
A[i] = 0;
i = ii = state = c = largest = 0;
while((c = getchar()) != EOF)
{
if(c == ' ' || c == '\b' || c == '\n')
{
if(state)
{
++A[i];
if(largest <= i)
largest = i;
i = state = 0;
}
}
else
{
if(state)
++i;
else
state = 1;
}
}
for(i = 0; i < 100; ++i)
if(highest <= A[i])
highest = A[i];
for(i = 0; i <= highest; ++i)
{
for(ii = 0; ii < 100; ++ii)
if(A[ii])
{
if(A[ii] > (highest - i))
printf("*\t");
else
printf(" \t");
}
putchar('\n');
}
for(ii = 0; ii < 100; ++ii)
if(A[ii])
printf("-\t");
putchar('\n');
for(ii = 0; ii < 100; ++ii)
if(A[ii])
printf("%d\t", ii + 1);
putchar('\n');
return 0;
}
Print Histogram based on word Length. (C Program).
HORIZONTAL VERSION :
#include<stdio.h>
#define MAX 15
int main()
{
int c, wordLength, count;
int arr[MAX] = { 0 };
wordLength = count = 0;
while((c = getchar()) != EOF)
{
if(c != ' ' && c != '\t' && c != '\n')
++arr[count];
else
++count;
}
for(int i = 0; i <= count; i++)
{
printf("\n%2d |", i+1);
for(int k = arr[i]; k > 0; k--)
printf("— ");
}
return 0;
}
Input/Output :
man in black thor jsjsk ksskka
1 |— — —
2 |— —
3 |— — — — —
4 |— — — —
5 |— — — — —
VERTICAL VERSION :
#include<stdio.h>
#define MAX 15
int main()
{
int c, count, maxLength;
int arr[MAX] = { 0 };
maxLength = count = 0;
while((c = getchar()) != EOF)
{
if(c != ' ' && c != '\t' && c != '\n')
++arr[count];
else
++count;
if(arr[count] > maxLength)
maxLength = arr[count];
}
for(int i = 1; i <= maxLength + 2; i++)
{
printf("\n");
for(int k = 0; k <= count; k++)
{
if(i <= maxLength)
{
if(maxLength - i < arr[k])
printf("|");
else
printf(" ");
}
else
{
if(maxLength - i == -1)
printf("—");
else
printf("%d", k+1);
}
printf(" ");
}
}
return 0;
}
Input/Output :
jsjs sjsj sjsj sjskks sjs sjs
|
|
| | | |
| | | | | |
| | | | | |
| | | | | |
— — — — — —
1 2 3 4 5 6
here is the method that I used :
#include <stdio.h>
#define MAXWD 25 // maximum words
#define MAXLW 20 // maximum lenght of word or characters
int main(void) {
int word[MAXWD]; // an array consists of 25 words
int c, i, j, nc, nw; // declaring c for the input, i for the loop 'for', j is for printing left to right, nc and nw stands for new character and new word
for (i = 0; i < 25; ++i)
word[i] = 0;
nc = nw = 0; // set to count from 0
while ((c = getchar()) != EOF) {
++nc;
if ( c == ' ' || c == '\t' || c == '\n') {
word[nw] = nc -1; // for deleting the space to go for the new word
++nw;
nc = 0; // start counting from zero
}
}
for (i = MAXLW; i >= 1; --i) {
for(j = 0; j <= nw; ++j) { // to start from left to wright
if (i <= word[j]) // MAXLW is less or equal to the number of words
putchar('|');
else
putchar(' ');
}
putchar ('\n');
}
return 0;
}