I have this sequence of letters and numbers, in which the letters are always these four: s, S, m, M. The numbers can have any value. Since the size of the sequence is not given, I just can't use a for loop, so I decided to use a while loop, but I'm having issues on breaking the loop.
Some input examples are:
12 s 80 s 3 m 12 M 240 S 8 m 30 s 240 s 1440 S 8 m 18 s 60 M
5 m 120 s 30 s 360 S 6 M 5 s 42 S 36 M 8 m 66 M 3240 S 14 m
Here is my code so far:
#include <stdio.h>
int main () {
int n[100], i = 0;
char x[100];
while(x[i] != '\n')
{
scanf(" %d %c", &n[i], &x[i]);
printf("%d %c ", n[i], x[i]);
i++;
}
return 0;
}
Any toughts on how to break the loop, and have all this values saved correctly on the array?
like this
#include <stdio.h>
int main(void){
int n[100], i, j;
char x[100];
do {
for(i = 0; i < 100; ++i){
int ch;
while((ch = getchar()) != EOF && ch != '\n'){//check newline
if(ch == '-' || '0' <= ch && ch <= '9'){
ungetc(ch, stdin);//back to stream a character
break;
}
}
if(ch == EOF || ch == '\n')
break;
if(2 != scanf("%d %c", &n[i], &x[i])){
fprintf(stderr, "invalid format.\n");
i = 0;//End the outer do-while loop
break;
}
}
//print
for(j = 0; j < i; ++j){
printf("(%d, %c)", n[j], x[j]);
}
printf("\n");
} while(i != 0);//End with empty line
}
#include <stdio.h>
#define DATA_MAX_LEN 100
int main(void){
int n[DATA_MAX_LEN], i, len, loop_end;
char x[DATA_MAX_LEN], newline[2], ch;
while(scanf("%1[\n]", newline) != 1){//End with empty line(only newline), Need EOF check
for(loop_end = len = i = 0; i < DATA_MAX_LEN && !loop_end; ++i){
//format: integer character[space|newline]
if(scanf("%d %c%c", &n[i], &x[i], &ch) != 3)
loop_end = printf("invalid format.\n");
else if(ch == '\n')
loop_end = len = ++i;
else if(ch != ' ')
loop_end = printf("invalid format.\n");
}
for(i = 0; i < len; ++i){
printf("%d %c ", n[i], x[i]);
}
printf("\n");
}
}
scanf and fscanf have many problems so it's best to avoid them.
The general pattern for dealing with input is to create a large input buffer, and then process that into smaller chunks.
char line[4096];
fgets( line, sizeof(line), stdin );
Since line is reused it's ok to make it large enough to hold any reasonable input.
Now that you've read a line into memory, it's a string of known size to process as you like. sscanf (scanf on a string) doesn't have most of the problems of scanf, but it's also not suited to moving through a string. One approach is to split the string into tokens on whitespace with strtok, and process them alternately as letters and numbers.
const char sep[] = " \t\n";
bool expect_letter = false;
for(
char *token = strtok( line, sep );
token != NULL;
token = strtok( NULL, sep )
) {
if( expect_letter ) {
printf("Letter %s\n", token);
expect_letter = false;
}
else {
printf("Number %s\n", token);
expect_letter = true;
}
}
If you want to store them in an array, it's bad practice to allocate what you hope is enough memory. You'll have to use an array that grows as needed. C does not have these built in. You can write your own, and it's a good exercise, but it's easy to get wrong. For production use one from a library such as Glib.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <glib.h>
int main() {
// Read a single line of input into a buffer.
char line[4096];
fgets( line, sizeof(line), stdin );
// Create arrays to hold letters and numbers, these will grow as needed.
GArray *numbers = g_array_new( FALSE, TRUE, sizeof(int) );
GArray *letters = g_array_new( FALSE, TRUE, sizeof(char) );
// Split the string on whitespace into tokens.
const char sep[] = " \t\n";
gboolean expect_letter = FALSE;
for(
char *token = strtok( line, sep );
token != NULL;
token = strtok( NULL, sep )
) {
if( expect_letter ) {
// Need an error check to ensure that `token` is a single character.
g_array_append_val( letters, token[0] );
expect_letter = FALSE;
}
else {
// strtol is a better choice, it has error checking
int num = atoi(token);
g_array_append_val( numbers, num );
expect_letter = TRUE;
}
}
// Print the numbers and letters.
for( guint i = 0; i < letters->len; i++ ) {
printf(
"%d%c\n",
g_array_index( numbers, int, i ),
g_array_index( letters, char, i )
);
}
}
Note that GLib provides its own boolean, so I switched to that instead of stdbool to keep things consistent.
As noted in the comments, this does not include checks that the token is what you expect. It's also possible to have a number with no letter, so checking that letters and numbers are the same size would be good. Or you can make a struct to hold the letter/number pairs and have a single list of those structs.
Related
For my assignment I need to modify the following program. I can not use strings.h.
int main(void)
{
int c, countSpaces = 0;
printf("Type sentence:\n");
do
{
c = getchar();
if (c == ' ')
countSpaces = countSpaces + 1;
}
while (c != '\n');
printf("Sentence contains %d Spaces.\n", countSpaces);
return 0;
}
I tried using
if (c != EOF)
countSpaces = countSpaces + 1;
}
while (c != '\n');
printf("Sentence contains %d Spaces.\n", countSpaces - 1);
but that seems like a hacky and unelegant way to do this.
Can anyone help and/or explain to me how to do this better?
Thanks in advance
The code I posted counts the spaces in a sentence, I want to modify it to count all the characters in the input sentence. – fbN 21 secs ago
Have another counter outside the if condition.
#include <stdio.h>
int main(void)
{
int c;
int countSpaces = 0;
int countChars = 0;
puts("Type sentence:");
do {
c = getchar();
countChars += 1;
if (c == ' ') {
countSpaces += 1;
}
} while (c != '\n');
printf("Sentence contains %d spaces and %d characters.\n", countSpaces, countChars);
return 0;
}
Two notes. foo += 1 is shorthand for foo = foo + 1 without the precendence complexities of foo++.
Blockless if or while is playing with fire. Eventually you'll accidentally write this.
if( condition )
do something
whoops this is not in the condition but it sure looks like it is!
Always use the block form.
$ ./test
Type sentence:
foo bar baz
Sentence contains 2 spaces and 12 characters.
Note this says 12 because it's including the newline. That's because it's checking what c is after it's already been counted. You can fix this by checking c as its read. This is a fairly normal "read and check" C loop idiom.
// Note, the parenthesis around `c = getchar()` are important.
while( (c = getchar()) != '\n' ) {
countChars++;
if (c == ' ') {
countSpaces++;
}
}
$ ./test
Type sentence:
foo bar baz
Sentence contains 2 spaces and 11 characters.
I always prefer to use fgets() when reading a line from the console (stdin):
#include <stdio.h>
int main(void)
{
int i;
int length = 0;
char buffer[1024];
printf( "Enter some text> " );
fgets( buffer, sizeof(buffer), stdin );
// If the user inputs > 1024 letters, buffer will not be \n terminated
for ( i=0; buffer[i] != '\n' && buffer[i] != '\0'; i++ )
{
length += 1;
}
printf( "length: %d\n", length );
return 0;
}
I make this code that count length of the string given It's like strlen function.
and I used just scanf and it works perfectly even with spaces.
#include <stdio.h>
int main()
{
char *str = calloc(sizeof(char),50);
int i = 0, count = 0;
printf("Type sentence:\n");
scanf("%[^\n]",str);
while (str[i++] != '\0')
count++; //length of the string
printf("%d",count);
return 0;
}
and if you want just to count the characters in the string given use this code below:
#include <stdio.h>
int main()
{
char *str = calloc(sizeof(char),50);
int count = 0;
printf("Type sentence:\n");
scanf("%[^\n]",str);
for (int i = 0; str[i] != '\0'; i++)
if ((str[i] >= 'A' && str[i] <= 'Z') || (str[i] >= 'a' && str[i] <= 'z'))
count++;
printf("Sentence contains %d characters.\n",count);
return 0;
}
the output :
Type sentence:
hello world
Sentence contains 10 characters.
you can just calculate the result like this
int main(void)
{
int c, countSpaces = 0;
printf("Type sentence:\n");
do
{
c = getchar();
if (c == ' ')
countSpaces++;
}
while (c != '\n');
int countChar = c - countSpaces - 1 ; // -1 new line
printf("Sentence contains %d Spaces.\n", countSpaces);
printf("Sentence contains %d chars.\n", countChar);
return 0;
}
I have a problem where I'm trying to turn a value from an array of string pointers to an integer value: token[1]. However, I get a segmentation fault whenever I don't specify an integer at the first index which in some cases I won't need a number. For example what if I just wanted to type the command: list. I would get a segmentation fault after. How do I store the convert the string value at token[1] to an integer, if an integer is present or not?
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
int main(){
int ch, n = 1;
int i = 0;
int val = 0;
char str[512], *token[5], *act_token;
while(1){
printf("Enter text: ");
while((ch = getchar()) != '\n')
str[i++] = ch;
str[i] = '\0';
i = 0;
printf("string: %s\n", str);
int spaces = 0;
for(int counter = 0; counter < strlen(str) + 1; counter++){
if(str[counter] == ' '){
spaces++;
}
}
printf("Spaces: %d\n", spaces);
strtok(str, " ");
while(n <= spaces && (act_token = strtok(NULL, " "))){
token[n] = act_token;
n++;
}
token[n] = NULL;
n = 1;
// printf("token[1]: %s\n", token[1]);
for(int x = 1; x < spaces+1; x++){
printf("token[%d]: %s\n", x, token[x]);
}
if(isdigit(atoi(token[1])) != 0){
val = atoi(token[1]);
}
printf("value:%d\n", val);
}
return 0;
}
I don't know whether I understand you correctly. However, I have simply added some checks to prevent segfault that were occurring at varying points of the code. Tested with 'foo 3 33'. Formatting is poor.
int main(){
int ch, n = 1;
int i = 0;
int val = 0;
#define TOKEN_SZ 5
char str[512], *token[TOKEN_SZ+1], *act_token;
while(1){
printf("Enter text: ");
while((ch = getchar()) != '\n')
str[i++] = ch;
str[i] = '\0';
i = 0;
printf("string: %s\n", str);
int spaces = 0;
for(int counter = 0; counter < strlen(str) + 1; counter++){
if(str[counter] == ' '){
spaces++;
}
}
printf("Spaces: %d\n", spaces);
n=0;
strtok(str, " ");
while(n<TOKEN_SZ && n <= spaces && (act_token = strtok(NULL, " "))){
token[n] = act_token;
n++;
}
token[n] = NULL;
for(int i=0; token[i]; i++){
printf("%d token[%d]: %s\n", n,i, token[i]);
}
if(n>0 && (atoi(token[0])) != 0){
val = atoi(token[0]);
}
printf("value:%d\n", val);
}
return 0;
}
Update
bash> ./a.out
Enter text: list 2 4
string: list 2 4
Spaces: 2
2 token[0]: 2
2 token[1]: 4
value:2
Enter text:
Replace
if(isdigit(atoi(token[1])) != 0){
val = atoi(token[1]);
}
with
if(isdigit(token[1][0])) != 0){
val = atoi(token[1]);
}
The problem is that isdigit takes a character as its argument. Sure, the man page says it takes an integer, but that integer represents a character.
What your code is doing is:
convert token[1] to an integer (or 0 if it's not a valid integer)
determine whether that integer happens to match an ASCII digit
If so, convert it again, and save the value.
I doubt that's your intent.
My version checks whether the first character of token[1] is a digit, and converts the value if it is. Make sure you understand what token[1][0] means.
BTW, note that if you enter more than 5 space-separated words in your string, you'll store to tokens[6] and higher, which will produce undefined results (possibly crash.) Also, your program is wrong if the user enters more than two spaces between words.
Don't guess what strtok is going to do regarding how it detects and handles delimiters. Instead, let it do its job. Store the values as you get them. Either pick a limit value for the array where you're storing your results and exit the loop before exceeding it, or malloc space for more results as necessary. Here's an example:
char * tstr = str;
int tok_count = 0;
char *tok;
do {
tok = strtok(tstr, " ");
if (tok != NULL) {
token[tok_count++] = tok;
}
tstr = NULL;
} while (tok != NULL && tok_count < TOK_COUNT);
TOK_COUNT has to be at least 1, and should be the array size for tokens.
I've been trying to get back into C lately (for work related purposes) and I've been to a C refresher workshop. I can't seem to get my head around why an infinite loop occurs in this code.
I'm trying to code a program which returns the number of words within an array of characters. Any help would be greatly appreciated. Thanks!
// ArrayWords.c
#include <stdio.h>
#include <ctype.h>
#define LENGTH 50
int word_count(char []);
int main(void) {
char sentence[LENGTH];
int i;
printf("Enter a sentence with at most %d characters:\n", LENGTH);
for(i = 0; i < LENGTH; i++)
scanf("%s", &sentence[i]);
printf("Sentence = %s\n", sentence);
printf("Word count = %d\n", word_count(sentence));
return 0;
}
// Count the number of words in str
int word_count(char str[]) {
int i, word = 1;
for(i = 0; i < LENGTH; i++)
while(str[i] != '\0')
if((isspace(str[i])))
{
word++;
}
return word;
}
Your use of scanf isn't good.
word_count cause infinite loop because i isn't updated in the while loop.
fixed code:
// ArrayWords.c
#include <stdio.h>
#include <ctype.h>
#define LENGTH 50
int word_count(char []);
int main(void) {
char sentence[LENGTH];
printf("Enter a sentence with at most %d characters:\n", LENGTH);
fgets(sentence, sizeof(sentence), stdin);
printf("Sentence = %s\n", sentence);
printf("Word count = %d\n", word_count(sentence));
return 0;
}
// Count the number of words in str
int word_count(char str[]) {
int i = 0, word = 1;
while(str[i] != '\0') {
if((isspace(str[i])))
{
word++;
}
i++;
}
return word;
}
for(i = 0; i < LENGTH; i++)
scanf("%s", &sentence[i]);
Here you are reading a char one by one. so it should have %c, like scanf(" %c", &sentence[i]);
However, this wont be the right way to read the string. Since, it wont put the \0 in the end.
Since the string to be read will contain spaces, best way to do this would be fgets()
Your counting loop also has an error, either you can change it to one of the answers above or simply use a single for loop, like this
for(i = 0; i < LENGTH && str[i] != '\0'; i++)
if((isspace(str[i])))
{
word++;
}
In your code,i isn't actually in the loop.Besides,array contains the sentence with a \0 in the end,so if the length of the sentence is 50,the space must be 51 since at the end of it there is an \0,and scanf is not so good as it judges " "as a stop sign,gets can't stop until enter key which may cause overflow,so I use fgets.
#include <stdio.h>
#include <ctype.h>
#define LENGTH 50
int word_count(char []);
int main(void) {
char sentence[LENGTH+1];
printf("Enter a sentence with at most %d characters:\n", LENGTH);
fgets(sentence, sizeof(sentence), stdin);
printf("Sentence = %s\n", sentence);
printf("Word count = %d\n", word_count(sentence));
return 0;
}
// Count the number of words in str
int word_count(char str[]) {
char* p=str;
int word=0;
while(*p!='\0'){
if((isspace(*p))) word++;
p++;
}
return word;
}
You should read data from stdin, not scanf but fgets or gets!
Maybe fgets( sentence, LENGTH, stdin ) is good.
And in the function word_count you may replace while with if.
This part of the program
for(i = 0; i < LENGTH; i++)
scanf("%s", &sentence[i]);
does not make sense. It tries to enter LENGTH number of words in the loop.
I think you mean format specifier %c instead of %s
scanf("%c", &sentence[i]);
but even in this case this snippet of code is wrong because the user can enter either less than LENGTH characters or even greater than LENGTH characters and the character array sentence will not be zero-terminated..
It is better to use standard function fgets instead of scanf in this situation.
And function word_count is also wrong. For example if str would be zero-terminated nevertheless the outer for loop will try to count words outside the string. And the function in fact counts the number of spaces. It is not the same as the number of words. A string can contain adjasted spaces. This mistake is made by all others in their answers.:)
And inside the while loop variable i is not increased. So it is an infinite loop.
int word_count(char str[]) {
int i, word = 1;
for(i = 0; i < LENGTH; i++)
while(str[i] != '\0')
if((isspace(str[i])))
{
word++;
}
return word;
}
The program can look the following way
// ArrayWords.c
#include <stdio.h>
#include <ctype.h>
#define LENGTH 50
size_t word_count( const char[] );
int main( void )
{
char sentence[LENGTH];
printf( "Enter a sentence with at most %d characters: ", LENGTH );
fgets( sentence, LENGTH, stdin );
printf( "Sentence = \"%s\"\n", sentence );
printf( "Word count = %zu\n", word_count( sentence ) );
return 0;
}
// Count the number of words in str
size_t word_count( const char s[] )
{
size_t words = 0;
while ( *s != '\0' )
{
// skip white spaces
while ( isspace( ( unsigned char )*s ) ) ++s;
if ( *s != '\0' ) ++words;
// skip the word
while ( *s != '\0' && !isspace( ( unsigned char )*s ) ) ++s;
}
return words;
}
Its output might look like
Enter a sentence with at most 50 characters: Hello, Unholy Wish
Sentence = "Hello, Unholy Wish"
Word count = 3
It's not an infinite loop.
Your program is trying to read 50 (or LENGTH) words (and saving them on top of each other).
for(i = 0; i < LENGTH; i++)
scanf("%s", &sentence[i]);
Put first word starting at sentence[0];
put second word starting at sentence[1] overwriting characters from the first word;
...
For example, the user shall put the input like that, "ABC123," but not "ABC 123" or "A BC123."
Here is my code:
unsigned int convert_to_num(char * string) {
unsigned result = 0;
char ch;
//printf("check this one %s\n", string);
while(ch =*string++) result = result * 26 + ch - 'A' + 1;
return result;
}
int main()
{
char input_string[100];
char arr_col[100] = {'\0'};
char arr_row[100] = {'\0'};
int raiseflag;
int started_w_alpha =0;
int digitflag = 0;
while(scanf("%s", &input_string) != EOF) {
int i = 0, j = 0, digarr = 0;
while (i <=5) {
if (input_string[i] == '\0') {printf("space found!");}
if ((input_string[i] >= 'A' && input_string[i] <= 'Z') && (digitflag == 0)) {
started_w_alpha = 1;
arr_col[j] = input_string[i]; j++;
}
//printf("something wrong here %s and %d and j %d\n", arr_holder, i, j);
if (started_w_alpha == 1) {
if (input_string[i] >=48 && input_string[i]<=57){ digitflag = 1; arr_row[digarr] =input_string[i]; digarr++; }
}
i++; if (i == 5) { raiseflag =1; }
}
printf(" => [%d,%s]\n", convert_to_num(arr_col), arr_row);
if (raiseflag == 1) { raiseflag = 0; memset(arr_col, 0, 5); memset(input_string, 0, 5); memset(arr_row, 0, 5); digitflag = 0; started_w_alpha = 0; }
}
return 0;
}
Apparently, \0 doesn't work in my case because I have an array of 5 and user can put 2 chars. I want to exit the loop whenever a space is found in between the characters.
This is the whole code. I added {'\0'} my array because of the extra characters I get when there is less than 5 characters.
Thanks!
Since the index is starting from 0 and input_string[5]; array size is 5, the only valid indexes are from 0 to 4.
but your loop while (i <=5) { go till 5, it is mean you exceed the array.
If you insert 5 characters to the string, the terminating null is the 6th.
Since you exceed the array it written over some other variable. but you still can find it when you check input_string[5]
So if you want to insert 5 characters you array size should be at least 6
char input_string[6];
if you want to check only the first 5 elements you'll have to change the loop to:
while (i < 5) {
and as I wrote in the comment if you find the terminating null, no use to continue the loop, since it contain garbage or leftover from the previous iteration.
Therefor you should break if it found, like this:
if (input_string[i] == '\0') {printf("space found!"); break;}
EDIT
check this program: it use fgets to read the whole input, then search for white spaces.
Note it doesn't trim the input, means it won't remove spaces when thay appear at the beginning or at the end of the input.
#include <ctype.h>
#include <string.h>
#include <stdio.h>
int main()
{
int i ,size;
char input_string[100];
fgets(input_string,100,stdin);
i=0;
size = strlen(input_string);
while (i<size-1){ //enter is also count
if (isspace(input_string[i]))
{
printf("space found!");
break;
}
i++;
}
return 0;
}
EDIT2
Now with a trim, so it will remove leading and ending spaces:
#include <ctype.h>
#include <string.h>
#include <stdio.h>
char* trim(char *input_string)
{
int i=0;
char *retVal = input_string;
i = strlen(input_string)-1;
while( i>=0 && isspace(input_string[i]) ){
input_string[i] = 0;
i--;
}
i=0;
while(*retVal && isspace(retVal[0]) ){
retVal ++;
}
return retVal;
}
int main()
{
int i ,size;
char input_string[100],*ptr;
fgets(input_string,100,stdin);
ptr = trim(input_string);
i=0;
size = strlen(ptr);
while (i<size){
if (isspace(ptr[i]))
{
printf("space found!");
break;
}
i++;
}
return 0;
}
I wrote the following to sort N integers read in from stdin in C, sort them using insertion-sort, and count the number of swaps that were needed to sort it for a SPOJ problem: http://www.spoj.com/problems/CODESPTB/
My code works for the sample inputs given and I've also tested with larger integer sets f larger values and everything seems to work fine. However, when I run it on SPOJ's online judge it fails with a Segmentation Fault at runtime. Unforunately, the creator of the problem on SPOJ has not made reviewing failures an option. I have no clue what's causing the seg fault. Does anything in my code jump out at you as to what might be causing it?
My Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_BUFF 100
int main(int argc, char *argv[]){
char buffer[MAX_BUFF];
char *long_str;
int T, N;
long *a;
printf("Enter a T value between 1 and 5 inclusive: ");
bzero(buffer, MAX_BUFF);
fgets(buffer, MAX_BUFF - 1, stdin);
T = atoi(buffer);
if(T<1 || T>5){
printf("Error: T must be 1<=T<=5\n");
exit(0);
}
const char delim[2] = " ";
char *token;
while(T > 0){
printf("Enter a N value between 1 and 100000 inclusive: ");
bzero(buffer,MAX_BUFF);
fgets(buffer, MAX_BUFF-1, stdin);
N = atoi(buffer);
if(N<1 || N>100000){
printf("Error: N must be 1<=N<=100000\n");
exit(0);
}
int current_size = 0;
long_str = malloc(MAX_BUFF);
current_size = MAX_BUFF;
printf("Enter N integers separated by spaces: ");
if(long_str != NULL){
int c = EOF;
unsigned int i = 0;
while(( c = getchar() ) != '\n' && c != EOF){
long_str[i++]=(char)c;
if(i==current_size){
current_size = i + MAX_BUFF;
long_str = realloc(long_str, current_size);
}
}
long_str[i] = '\0';
}
token = strtok(long_str, delim);
a[0]=atol(token);
int i = 1;
while (token != NULL && i < N) {
token = strtok(NULL, delim);
if(token == NULL){
printf("Error, not enough ints specified, terminating\n");
exit(0);
}
a[i] = atol(token);
i++;
}
free(long_str);
int j, tmp, count;
count = 0;
for(i=1; i<N; i++){
j=i;
while(j>0 && a[j]<a[j-1]){
tmp = a[j];
a[j] = a[j-1];
a[j-1] = tmp;
j--;
count++;
}
}
T--;
}
}
You never allocate space for a:
long *a;
...
a[0]=atol(token);
...
a[i] = atol(token);
Unfortunately, one possibility of undefined behaviour is that it "seems to work fine".