BUG IN DEVC++ (Comparing String and Character) - c

I'm trying to make a program that will count how many letters occur in my string. I want only to count letters A and B on a give string.
char string[10];
int countA, countB;
gets(string);
for(int i = 0; i <strlen(string); i++){
if(string[i] == 'A')
countA++;
else if(string[i] == 'B')
countB++;
}
printf("%d %d", countA, countB);
return 0;
for example my input is: ABABA
the output should be 3 2 however it print a different answer for countB. I'm using devc++. Is this a bug?

Reason for getting different result:
Earlier when you didn't initialize the variable countA and countB they contained indeterminate value. Using them in your code introduces undefined behavior.
Two points:
Intialize the variables to zero. countA and countB.
And don't use gets rather use fgets.
I am giving you an example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main(){
char string[10];
unsigned int countA=0, countB=0;
if( fgets(string,10,stdin) == NULL){
fprintf(stderr, "%s\n", "Error in string input");
exit(1);
}
size_t len = strlen(string);
if( len > 0 )
string[len-1]='\0';
for(size_t i = 0; i <strlen(string); i++){
if(string[i] == 'A'){
countA++;
}
else if(string[i] == 'B'){
countB++;
}
}
printf("%u %u", countA, countB);
return EXIT_SUCCESS;
}
Note:
Also you are asked whether it is gloabal variable. If it was then probably you wouldn't have to worry about initialization. They would be initialized with 0.
gets() goes on reading characters until it encounters \n or EOF. And on doing this it is not constrained in anyway with the buffer size, leaving a chance of buffer overflow.

Related

Why is this code producing an infinite loop?

#include <Stdio.h>
#include <string.h>
int main(){
char str[51];
int k = 1;
printf("Enter string\n");
scanf("%s", &str);
for(int i = 0; i < strlen(str); i++){
while(str[k] != '\0')){
if(str[i] == str[k]){
printf("%c", str[i]);
k++;
}
}
}
return 0;
}
It is simple C code that checks for duplicate characters in string and prints the characters. I am not understanding why it is producing an infinite loop. The inner while loop should stop when str[k] reaches the null terminator but the program continues infinitely.
Points to know
You don't need to pass the address of the variable str to scanf()
Don't use "%s", use "%<WIDTH>s", to avoid buffer-overflow
Always check whether scanf() conversion was successful or not, by checking its return value
Always use size_t to iterator over any array
i < strlen(str), makes the loop's time complexity O(n3), instead of O(n2), which also isn't very good you should check whether str[i] != 0. But, many modern compilers of C will optimize it by the way.
#include <Stdio.h> it is very wrong, stdio.h != Stdio.h
Call to printf() can be optimized using puts() and putc() without any special formatting, here also modern compiler can optimize it
while(str[k] != '\0')){ has a bracket (')')
Initialize your variable str using {}, this will assign 0 to all the elements of str
Better Implementation
My implementation for this problem is that create a list of character (256 max) with 0 initialized, and then add 1 to ASCII value of the character (from str) in that list. After that print those character whose value was greater than 1.
Time Complexity = O(n), where n is the length of the string
Space Complexity = O(NO_OF_CHARACTERS), where NO_OF_CHARACTERS is 256
Final Code
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
static void print_dup(const char *str)
{
size_t *count = calloc(1 << CHAR_BIT, sizeof(size_t));
for(size_t i = 0; str[i]; i++)
{
count[(unsigned char)str[i]]++;
}
for (size_t i = 0; i < (1 << CHAR_BIT); i++)
{
if(count[i] > 1)
{
printf("`%c`, count = %zu\n", i, count[i]);
}
}
free(count);
}
int main(void) {
char str[51] = {};
puts("Enter string:");
if (scanf("%50s", str) != 1)
{
perror("bad input");
return EXIT_FAILURE;
}
print_dup(str);
return EXIT_SUCCESS;
}
Read your code in English: You only increment variable k if character at index k is equal to character at index i. For any string that has different first two characters you will encounter infinite loop: char at index i==0 is not equal to char at index k==1, so k is not incremented and while(str[k]!=0) loops forever.

Loop counter or break statement is not working

I'm trying to write a program that takes in user input from keyboard, stores it in a 2D array, and prints it in revers order. So, if a user typed in:
Line 1
Line 2
The output would be:
Line 2
Line 1
However, I'm stuck on a break condition in my if statement inside the first for loop. Even though I type in "STOP" the program still waits for input. I assume the problem might be due to strcmp function because when I print out the value returned from the function, I'm not getting zero even though my input was "STOP".
#include <stdio.h>
#include <string.h>
int main(){
int i, words = 500, characters = 100, arraylen;
char array[words][characters];
arraylen = sizeof(array)/sizeof(array[0][0]);
printf("Enter lines of words( type \"STOP\" to quit):\n");
for(i = 0; i < arraylen; i++){
fgets(array[i], 100, stdin);
//printf("Value at index %d is %s", i, array[i]);
//printf("Value of strcmp: %d\n", strcmp(array[i], "STOP"));
if(strcmp(array[i], "STOP") == 0){
//if(fgets(array[i], 500, stdin) == "STOP")
break;
}
}
printf("\n");
for(i = arraylen - 1; i >= 0; i--){
printf("%s", array[i]);
}
printf("\n");
return 0;
}
The maximum length of array is really just the value of words.
You also need to need to keep track of how many entries you've added so that you do not run out of space, and so that you can know which position to start printing from, afterwards. As is, you are attempting to print from the very end of the array, from memory that may not have been initialized.
fgets places the newline character ('\n'), if read, in the buffer. You'll either need to remove it, or use strncmp to limit your comparison to the length of your sentinel string.
if (strncmp(buffer, "STOP", 4)) {
/* .. */
}
fgets can also fail, returning NULL to signal this. You need to check its return value in some way, and act appropriately.
An example program:
#include <stdio.h>
#include <string.h>
#define MAX_LEN 500
#define STR_LEN 100
int main(void) {
char strings[MAX_LEN][STR_LEN];
size_t i = 0;
printf("Enter lines of words( type \"STOP\" to quit):\n");
while (i < MAX_LEN && fgets(strings[i], STR_LEN, stdin)) {
strings[i][strcspn(strings[i], "\n")] = '\0';
if (strcmp(strings[i], "STOP") == 0)
break;
i++;
}
while (i--)
printf("%s\n", strings[i]);
}

Code Blocks error when using while(scanf) in C

I have attached a piece of code below which works perfectly fine in an online compiler but fails to work in Code Blocks compiler when using C. I have attached screenshots as well.
#include <stdio.h>
int main() {
int i = 0;
int array[100];
while(scanf("%d",&array[i])>0)
{
i++;
}
for(int j=0;j<i;j++)
{
printf("%d ",array[j]);
}
return 0;
}
Using Online compiler(GeeksForGeeks)
Using CODEBLOCKS compiler
There is no error, your while loop will go on until an invalid input is entered, you have no limit for the number of inputs so it will continue taking values, which may later become a problem since your container only has space for 100 ints.
It stops on some online compilers because of the way they use stdin inputs, it's basically a one time readout.
Examples:
It stops here, has one time stdin readout.
It doesn't stop here, has a console like input/output.
So if you want to stop at a given number of inputs you can do something like:
//...
while (i < 5 && scanf(" %d", &array[i]) > 0)
{
i++;
}
//...
This will read 5 ints, exit the loop and continue to the next statement.
If you don't really know the number of inputs, you can do something like:
//...
while (i < 100 && scanf("%d", &array[i]) > 0) { // still need to limit the input to the
// size of the container, in this case 100
i++;
if (getchar() == '\n') { // if the character is a newline break te cycle
// note that there cannot be spaces after the last number
break;
}
}
//...
The previous version lacks some error checks so for a more comprehensive approach you can do somenthing like this:
#include <stdio.h>
#include <string.h> // strcspn
#include <stdlib.h> // strtol
#include <errno.h> // errno
#include <limits.h> // INT_MAX
int main() {
char buf[1200]; // to hold the max number of ints
int array[100];
char *ptr; // to iterate through the string
char *endptr; // for strtol, points to the next char after parsed value
long temp; //to hold temporarily the parsed value
int i = 0;
if (!fgets(buf, sizeof(buf), stdin)) { //check input errors
fprintf(stderr, "Input error");
}
ptr = buf; // assing pointer to the beginning of the char array
while (i < 100 && (temp = strtol(ptr, &endptr, 10)) && temp <= INT_MAX
&& errno != ERANGE && (*endptr == ' ' || *endptr == '\n')) {
array[i++] = temp; //if value passes checks add to array
ptr += strcspn(ptr, " ") + 1; // jump to next number
}
for (int j = 0; j < i; j++) { //print the array
printf("%d ", array[j]);
}
return EXIT_SUCCESS;
}

fetching string and converting to double

I'm trying to create a function which can determine if an input can be converted perfectly into a double and then be able to store it into an array of doubles. For example, an input of "12.3a" is invalid. From what I know, strtod can still convert it to 12.3 and the remaining will be stored to the pointer. In my function doubleable, it filters whether the input string consists only of digits. However, I'm aware that double has "." like in "12.3", and my function will return 'X' (invalid).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char doubleable (char unsure[], int length){
int i;
int flag;
for (i=0; i<length; i++ ){
if(isdigit(unsure[i]==0)){
printf("You have invalid input.\n");
flag=1;
break;
}
}
//check for '.' (?)
if(flag==1)
return 'X';
else
return 'A';
}
int main(){
char input [10];
double converted[5];
char *ptr;
int i;
for(i=0; i<5; i++){
fgets(input, 10, stdin);
//some code here to replace '\n' to '\0' in input
if(doubleable(input, strlen(input))=='X'){
break;
}
converted[i]=strtod(input, &ptr);
//printf("%lf", converted[i]);
}
return 0;
}
I'm thinking of something like checking for the occurrence of "." in input, and by how much (for inputs like 12.3.12, which can be considered invalid). Am I on the right track? or are there easier ways to get through this? I've also read about the strtok function, will it be helpful here? That function is still quite vague to me, though.
EDIT:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
double HUGE_VAL= 1000000;
void string_cleaner (char *dirty){
int i=0;
while(1){
if (dirty[i]=='\n'){
dirty[i]='\0';
break;
}
i++;
}
}
int doubleable2(const char *str)
{
char *end_ptr;
double result;
result = strtod(str, &end_ptr);
if (result == HUGE_VAL || result == 0 && end_ptr == str)
return 0; // Could not be converted
if (end_ptr < str + strlen(str))
return 0; // Other input in the string after the number
return 1; // All of the string is part of the number
}
int main(){
char input [10];
double converted[10];
char *ptr;
int i;
for(i=0; i<5; i++){
while (1){
printf("Please enter:");
fgets(input, 10, stdin);
string_cleaner(input);
if (doubleable2(input)==0)
continue;
else if (doubleable2(input)==1)
break;
}
converted[i]=strtod(input, &ptr);
printf("%lf\n", converted[i]);
}
return 0;
}
thank you! It works just fine! I have a follow up question. If I enter a string that is too long, the program breaks. If I am to limit the input to, let's say, a maximum of 9 characters in input[], how am I to do that?
from what I understand about fgets(xx, size, stdin), it only gets up to size characters (including \n, \0), and then stores it to xx. In my program, I thought if I set it to 10, anything beyond 10 will not be considered. However, if I input a string that is too long, my program breaks.
You can indeed use strtod and check the returned value and the pointer given as the second argument:
int doubleable(const char *str)
{
const char *end_ptr;
double result;
result = strtod(str, &end_ptr);
if (result == HUGE_VAL || result == 0 && end_ptr == str)
return 0; // Could not be converted
if (end_ptr < str + strlen(str))
return 0; // Other input in the string after the number
return 1; // All of the string is part of the number
}
Note that you need to remove the newline that fgets most of the time adds to the string before calling this function.
From what I know, strtod can still convert it to 12.3 and the remaining will be stored to the pointer.
That is correct – see its man page:
If endptr is not NULL, a pointer to the character after the last character used in the conversion is stored in the location referenced by endptr.
So use that information!
#include <stdio.h>
#include <stdbool.h>
#include <errno.h>
bool doable (const char *buf)
{
char *endptr;
errno = 0;
if (!buf || (strtod (buf, &endptr) == 0 && errno))
return 0;
if (*endptr)
return 0;
return 1;
}
int main (void)
{
printf ("doable: %d\n", doable ("12.3"));
printf ("doable: %d\n", doable ("12.3a"));
printf ("doable: %d\n", doable ("abc"));
printf ("doable: %d\n", doable (NULL));
return 0;
}
results in
doable: 1
doable: 0
doable: 0
doable: 0
After accept answer
Using strtod() is the right approach, but it has some challenges
#include <ctype.h>
#include <stdlib.h>
int doubleable3(const char *str) {
if (str == NULL) {
return 0; // Test against NULL if desired.
}
char *end_ptr; // const char *end_ptr here is a problem in C for strtod()
double result = strtod(str, &end_ptr);
if (str == end_ptr) {
return 0; // No conversion
}
// Add this if code should accept trailing white-space like a \n
while (isspace((unsigned char) *endptr)) {
endptr++;
}
if (*end_ptr) {
return 0; // Text after the last converted character
}
// Result overflowed or maybe underflowed
// The underflow case is not defined to set errno - implementation defined.
// So let code accept all underflow cases
if (errno) {
if (fabs(result) == HUGE_VAL) {
return 0; // value too large
}
}
return 1; // Success
}
OP's code
No value with result == 0 in result == 0 && end_ptr == str. Simplify to end_ptr == str.
Instead of if (end_ptr < str + strlen(str)), a simple if (*end_ptr) is sufficient.
if (result == HUGE_VAL ... is a problem for 2 reasons. 1) When result == HUGE_VAL happens in 2 situations: A legitimate conversion and an overflow conversion. Need to test errno to tell the difference. 2) the test should be if (fabs(result) == HUGE_VAL ... to handle negative numbers.

gets() problem in C

I wrote the following code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 128
int main ()
{
char mychar , string [SIZE];
int i;
int const count =0 ;
printf ("Please enter your string: \n\n");
fgets (string, SIZE, stdin);
printf ("Please enter char to find: ");
mychar = getchar();
for (i=0 ; (string[i] == '\0') ; i++ )
if ( string[i] == mychar )
count++;
printf ("The char %c appears %d times" ,mychar ,count);
return 0;
}
The problem is that the gcc gives me an error for the 'int const count': " increment of read-only variable ‘count’".
What seems to be wrong ?
Thank !
Try using fgets instead as:
fgets (string, SIZE, stdin);
Why gets is unsafe, has been answered several times on SO. You can see this.
Always use fgets() instead of gets. Also there are lots of stuff to fix. You shouldnt use standard library functions for creating user interface. Standard library is really not designed for that. Instead you should use curses library or something similar. You could also write the program to accept arguments as input.
Short example of proper use of the standard library. This version does not have any error checking so it assumes that user input is correct.
#include <stdio.h>
int main(int artc, char *argv[])
{
/* arguments are strings so assign only the first characte of the
* third argument string. Remember that the first argument ( argv[0] )
* is the name of the program.
*/
char mychar = argv[2][0];
char *string = argv[1];
int i, count = 0;
/* count the occurences of the given character */
for(; *string != '\0'; ++string)
if(*string == mychar) ++count;
printf("The char ‘%c’ appears %d times.\n", mychar, count);
return 0;
}
Usage: ./count "Hello, World!" l
Output: The char ‘l’ appears 3 times.
EDIT: As for the original code. Change == to !=.
for (i=0 ; (string[i] == '\0') ; i++ )
to:
for (i=0 ; (string[i] != '\0') ; i++ )
The comparison was wrong.
To make this example work you should also change the line:
if(*string == mychar) ++count;
into
if(string[i] == mychar) ++count;
Full working example is now:
#include <stdio.h>
int main(int artc, char *argv[])
{
/* arguments are strings so assign only the first characte of the
* third argument string. Remember that the first argument ( argv[0] )
* is the name of the program.
*/
char mychar = argv[2][0];
char *string = argv[1];
int i, count = 0;
/* count the occurences of the given character */
for (i=0 ; (string[i] != '\0') ; i++ )
if(string[i] == mychar) ++count;
printf("The char ‘%c’ appears %d times in the sentence: %s\n", mychar, count, string);
return 0;
}
Consider replace with "scanf( "%s", &string)" instead.
gets is dangerous because it lets you read in more data than you've allocated space for, you can use fgets which specifies how many characters it is going to read in and stops if it finds a newline.
gets is dangerous because it can take in more data than the size of the variable. Thereby exposing the system to attacks and compromising security.
fgets should be used as it limits no. of characters to be read.
This will do:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 128
int main()
{
char mychar, string[SIZE];
int i;
int count=0;
printf("Please enter your string: ");
fgets(string, SIZE, stdin);
printf("Please enter char to find: ");
mychar = getchar();
for (i = 0; (string[i] != '\0'); i++)
if (string[i] == mychar) ++count;
printf("The char %c appears %d times in the sentence: %s" ,mychar ,count, string);
return 0;
}

Resources