Code Blocks error when using while(scanf) in C - 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;
}

Related

Newbie here. C function problem during execution

Edit: Since I understand that I need to provide more info to make it clear for you guys, I added the main function and the getchoice and also two images of the program running. My problem is that after entering the endword, I want to see the menu first and then make a choice, whereas it prompts me to give an input without showing the menu.
This function is part of a bigger program, but this is where a problem occurs.
It reads words inputed, places them into an array, until the keyword ****END is entered. However, when this keyword is entered, it doesn't go immediatelly in the specified if clause (you will see that in the code). I'm a newbie and it could be something really obvious, but any help is greatly appreciated.
#include <string.h>
#define M 50
#define N 15
void getText(char a[M][N])
{
int i, j;
char temp[N];
for (i = 0; i < 50; i++) {
for (j = 0; j < 15; j++) {
if (i == 49 && j == 14) {
printf("Maximum length of text reached.\n");
}
scanf("%s\n", temp);
if (strcmp(temp, "****END") == 0) {
printf("You entered the endkey.\n");
return;
}
strcpy(a[i], temp);
}
}
}
int main(){
int input;
while(1){
input = getChoice();
if(input == 1){
getText(text);
}
else if(input == 2){
getDictionary();
}
else if(input == 3){
correctText();
}
else if(input == 4){
saveText();
}
else if(input == 5){
getStats();
}
else if(input == 6){
break;
}
}
return 0;
}
int getChoice(){
int temp;
printf("Choose function:\n1: Enter text\n2: Enter dictionary\n3: Correct text\n4: Save text\n5: Get text statistics\n6: Exit program\n");
scanf("%d", &temp);
return temp;
}
Entered the endword and now it waits for input instead of showing the menu.
I inputed 2 for the second program function, then it showed the menu and proceeded to function 2.
Apart from the unnecessary double-nested loop, this line
scanf("%s\n", temp);
should be
scanf("%s", temp);
Usually, you should not try to match trailing whitespace with scanf, and the format specifier %s automatically filters out leading whitespace (but note that %c does not).
There are other faults and the code presented was originally incomplete, but notably the input length for %s must be restricted to prevent buffer overflow.
#include <stddef.h> // size_t
#include <ctype.h> // isspace()
#include <stdio.h> // scanf(), puts()
#include <string.h> // strcmp()
// see https://stackoverflow.com/questions/2653214/stringification-of-a-macro-value
#define STRINGIFY(x) #x
#define STRING(x) STRINGIFY(x)
#define LINES 50
#define COLS 15
char const *end = "****END";
// throw away everything until a newline is found
void clear(FILE *stream)
{
int ch;
while ((ch = getc(stream)) != EOF && ch != '\n');
}
size_t getText(char dst[LINES][COLS + 1])
{
size_t i = 0;
for (; i < LINES; i++) {
char temp[COLS + 1] = { 0 };
scanf("%" STRING(COLS) "s", temp); // "%15s" at runtime.
int ch;
// if the next character is not whitespace ...
if ((ch = getchar()) != EOF && !isspace(ch)) {
puts("Warning: Input too long, was truncated!");
clear(stdin);
}
if (strcmp(temp, end) == 0) {
puts("You entered the endkey.");
return i;
}
strcpy(dst[i], temp);
}
return i;
}
int main(void)
{
// COLS + 1 ... we need space for the terminating newline character.
char foo[LINES][COLS + 1];
size_t n = getText(foo);
for (size_t i = 0; i < n; ++i)
puts(foo[i]);
}
The %s conversion specifier should never be used without specifying a width to limit the characters that get stored:
char foo[10];
scanf("%9s");

Memory limit exceeded in C

I'm currently being a tutor for a student in C. For his classes, the university has installed a server running Mooshak (software capable of receiving code and test it).
We have developed code, compiled it and tested it locally before sending to the server and everything went fine. However, when we tried to send it to the server, the server stated "Memory Limit Exceeded".
The code looked as follows:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <limits.h>
#include <string.h>
#define LIMITE_CARACTERES 1000
#define LIMITE_GENES 100000
char genes[LIMITE_GENES][LIMITE_CARACTERES];
char* copiar_por_espaco(char* string, char* dest)
{
for(int i = 0; i < strlen(string); i++)
{
if(' ' == string[i])
{
strncpy(dest, string, i);
dest[i] ='\0';
if( i + 1 >= strlen(string))
return NULL;
else
return &string[i+1];
}
}
if(strlen(string) == 0)
{
return NULL;
}
else
{
strcpy(dest, string);
return NULL;
}
}
void genes_f()
{
char s[LIMITE_CARACTERES];
int numero_genes = 0;
while(scanf("%s", s) != EOF)
{
char *auxiliar = s;
while(auxiliar != NULL && strlen(auxiliar) != 0)
{
auxiliar = copiar_por_espaco(auxiliar, genes[numero_genes]);
numero_genes++;
}
}
if(numero_genes <= 20)
{
for(int i = 0; i < numero_genes; i++)
{
printf("%s\n", genes[i]);
}
}
else
{
for(int i = 0; i < 10; i++)
{
printf("%s\n", genes[i]);
}
for(int i = numero_genes - 10; i < numero_genes;i++)
{
printf("%s\n", genes[i]);
}
}
}
int main()
{
genes_f();
return 0;
}
Please note that the values LIMITE_CARACTERES and LIMITE_GENES are an assignment requirement (they haven't been told about memory allocation yet). The above code gives the "Memory Limit Exceeded", but if I split the first four into two lines, the server does not throw that error and accepts our solution:
char* copiar_por_espaco(char* string, char* dest)
{
int len = strlen(string); // This line was taken out from the for
for(int i = 0; i < len; i++) // Now we used the variable instead
{
if(' ' == string[i])
{
strncpy(dest, string, i);
dest[i] ='\0';
if( i + 1 >= strlen(string))
return NULL;
else
return &string[i+1];
}
}
if(strlen(string) == 0)
{
return NULL;
}
else
{
strcpy(dest, string);
return NULL;
}
}
I have no idea why. Is there an explanation for this?
The input will several lines with words (blank lines should be skipped), separated by a space. The program should separate and take each word:
Input
A BDD TES QURJ
test dog cat heart
cow
bird tree
Output
A
BDD
TES
QURJ
test
dog
cat
heart
cow
bird
tree
You forgot to include an extra byte for null terminators in your array. If LIMITE_CARACTERES is the maximum length of a string provided as input, then you need an array of size LIMITE_CARACTERES + 1 in which to store it. So you need to change this line
char genes[LIMITE_GENES][LIMITE_CARACTERES];
to
char genes[LIMITE_GENES][LIMITE_CARACTERES + 1];
Since you are a tutor, I give feedback so you can properly teach your student (so this is not an answer to your problem).
copiar_por_espaco
for(int i = 0; i < strlen(string); i++)
Repeatedly calling strlen on a variable that does not change in the loop is a waste of CPU cycles. Indeed, you should calculate the length before the loop and use it in the loop. That also holds for if( i + 1 >= strlen(string))
if(' ' == string[i])...
Note that it is guaranteed the string does not hold spaces because it was read with scanf. As a consequence, the function will always return NULL.
if(strlen(string) == 0) return NULL;
You test this after the loop but logic dictates you do this before any processing and it could be shortened to if (!*string) return NULL; This would also make the code more beautiful as the else part is not needed (it is not needed anyway).
genes_f
while(scanf("%s", s) != EOF)
A scanf-guru might help here but I believe there must be a space in the format specifier so it will skip leading spaces, " %s". I believe your way will read only one string and then will loop indefinitely returning zero on each scanf call. You should test the result of scanf for the number of format specifiers successfully converted and not for EOF. So check for 1.
if(numero_genes <= 20)
Your printing is funny. It all can be as one loop:
for(int i = numero_genes; i < numero_genes; i++)
printf("%s\n", genes[i]);
You have to do bounds checks on your number of genes:
numero_genes<LIMITE_GENES

Input to array of strings won't show?

I'm in C and I'm supposed to have an input of numbers (don't know how many) formatted into one column without storing them into an array of integers. I can't figure out why my code won't read the input and out put it. Please help.
#include <stdio.h>
#include <stdlib.h>
int main() {
int i;
char *nums[400];
for (i=0; i<nums; i++) {
scanf(nums[i]);
printf( "%.*s", 3, nums[i] );
}
return 0;
}
You have an array of 400 pointers, but you've never initialized them. Instead, you could declare a 2-dimension array:
char nums[400][4];
Then you're trying to use nums as a limit to the for loop. What you actually want is the number of elements in nums, which is sizeof(nums)/sizeof(nums[0]); or you could define a macro that specifies the size of the array.
Next, you left out the format string argument to scanf().
#include <stdio.h>
#include <stdlib.h>
#declare SIZE 400
int main()
{
int i;
char *nums[SIZE][4];
for(i=0; i<SIZE; i++){
scanf("%3s", nums[i]);
printf( "%.*s", 3, nums[i] );
}
return 0;
}
As Baramar correctly and thoroughly explained your main problems, I think I might have a different understanding of your problem. You want a given string of number, e.g.: 2134567896543245678 and print it out in a single column, neatly formated in rows of three digits each like that:
213
456
789
654
324
567
8
without an intermittent array of integers.
That could be done like e.g.: this
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFER_SIZE 512
int main()
{
int res;
// for the scanf input, set all to '\0'
char buffer[BUFFER_SIZE + 1] = { '\0' }, *idx;
size_t len, i;
// restrict max-size to BUFFER_SIZE
res = scanf("%512s", buffer);
if (res != 1) {
exit(EXIT_FAILURE);
} else {
if (strcmp(buffer, "exit") == 0) {
exit(EXIT_SUCCESS);
}
// TODO: check if the buffer contains all digits
len = strlen(buffer);
idx = buffer;
for (i = len; i >= 3; i -= 3, idx += 3) {
printf("%.3s\n", idx);
}
// last entries, if any
if (*idx != '\0') {
printf("%s\n", idx);
}
}
exit(EXIT_SUCCESS);
}
If you get actual integers in a row like e.g.: 12 3123 23478 34 5456 567456 567 678 you can use something like that:
EDIT
After the comment by the OP to use floating points I changed the code to accept input of the form:
24722.319352 51433.662233
56087.991042 49357.684934 67875.375848 68421.563197
54521.615295
22744.470483
38097.001461 80878.250982
92131.575748 7217.137271
20750.671365 7620.695008 37118.391541 28655.609469 46885.110202 87114.202312
46462.577299
20557.716648
And the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXNUM 400
int main()
{
int res;
int i = 0, m;
// input and two temporary variables
double in, in1, in2;
for (m = 0; m < MAXNUM; m++) {
res = scanf("%lf", &in);
if (res != 1) {
break;
} else {
switch (i) {
case 0:
// set value of first temporary variable to input
in1 = in;
// increment indicator indicating position in output row
i++;
break;
case 1:
in2 = in;
i++;
break;
case 2:
// print the three numbers and a newline
fprintf(stdout, "%f %f %f\n", in1, in2, in);
// reset counter
i = 0;
break;
}
}
}
// if there are still numbers, print them
if (i != 0) {
if (i == 1) {
fprintf(stdout, "%f\n", in1);
} else {
fprintf(stdout, "%f %f\n", in1, in2);
}
}
exit(EXIT_SUCCESS);
}
Try it out with
$ gcc-4.9 -O3 -g3 -W -Wall -Wextra -std=c11 sc.c -o sc
$ ./sc < floatin
24722.319352 51433.662233 56087.991042
49357.684934 67875.375848 68421.563197
54521.615295 22744.470483 38097.001461
80878.250982 92131.575748 7217.137271
20750.671365 7620.695008 37118.391541
28655.609469 46885.110202 87114.202312
46462.577299 20557.716648
If you enter less than 400 entries you need to end with EOF which can be triggered in most Unix shells with ctrl+d or set an entry to end the entries like e.g.: -1 if all you have is positive numbers and check for it to break out of the loop. If you submit a file like in the example above it works automatically.

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.

Program runs too slowly with large input - C

The goal for this program is for it to count the number of instances that two consecutive letters are identical and print this number for every test case. The input can be up to 1,000,000 characters long (thus the size of the char array to hold the input). The website which has the coding challenge on it, however, states that the program times out at a 2s run-time. My question is, how can this program be optimized to process the data faster? Does the issue stem from the large char array?
Also: I get a compiler warning "assignment makes integer from pointer without a cast" for the line str[1000000] = "" What does this mean and how should it be handled instead?
Input:
number of test cases
strings of capital A's and B's
Output:
Number of duplicate letters next to each other for each test case, each on a new line.
Code:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
int main() {
int n, c, a, results[10] = {};
char str[1000000];
scanf("%d", &n);
for (c = 0; c < n; c++) {
str[1000000] = "";
scanf("%s", str);
for (a = 0; a < (strlen(str)-1); a++) {
if (str[a] == str[a+1]) { results[c] += 1; }
}
}
for (c = 0; c < n; c++) {
printf("%d\n", results[c]);
}
return 0;
}
You don't need the line
str[1000000] = "";
scanf() adds a null terminator when it parses the input and writes it to str. This line is also writing beyond the end of the array, since the last element of the array is str[999999].
The reason you're getting the warning is because the type of str[10000000] is char, but the type of a string literal is char*.
To speed up the program, take the call to strlen() out of the loop.
size_t len = strlen(str)-1;
for (a = 0; a < len; a++) {
...
}
str[1000000] = "";
This does not do what you think it does and you're overflowing the buffer which results in undefined behaviour. An indexer's range is from 0 - sizeof(str) EXCLUSIVE. So you either add one to the
1000000 when initializing or use 999999 to access it instead. To get rid of the compiler warning and produce cleaner code use:
str[1000000] = '\0';
Or
str[999999] = '\0';
Depending on what you did to fix it.
As to optimizing, you should look at the assembly and go from there.
count the number of instances that two consecutive letters are identical and print this number for every test case
For efficiency, code needs a new approach as suggeted by #john bollinger & #molbdnilo
void ReportPairs(const char *str, size_t n) {
int previous = EOF;
unsigned long repeat = 0;
for (size_t i=0; i<n; i++) {
int ch = (unsigned char) str[i];
if (isalpha(ch) && ch == previous) {
repeat++;
}
previous = ch;
}
printf("Pair count %lu\n", repeat);
}
char *testcase1 = "test1122a33";
ReportPairs(testcase1, strlen(testcase1));
or directly from input and "each test case, each on a new line."
int ReportPairs2(FILE *inf) {
int previous = EOF;
unsigned long repeat = 0;
int ch;
for ((ch = fgetc(inf)) != '\n') {
if (ch == EOF) return ch;
if (isalpha(ch) && ch == previous) {
repeat++;
}
previous = ch;
}
printf("Pair count %lu\n", repeat);
return ch;
}
while (ReportPairs2(stdin) != EOF);
Unclear how OP wants to count "AAAA" as 2 or 3. This code counts it as 3.
One way to dramatically improve the run-time for your code is to limit the number of times you read from stdin. (basically process input in bigger chunks). You can do this a number of way, but probably one of the most efficient would be with fread. Even reading in 8-byte chunks can provide a big improvement over reading a character at a time. One example of such an implementation considering capital letters [A-Z] only would be:
#include <stdio.h>
#define RSIZE 8
int main (void) {
char qword[RSIZE] = {0};
char last = 0;
size_t i = 0;
size_t nchr = 0;
size_t dcount = 0;
/* read up to 8-bytes at a time */
while ((nchr = fread (qword, sizeof *qword, RSIZE, stdin)))
{ /* compare each byte to byte before */
for (i = 1; i < nchr && qword[i] && qword[i] != '\n'; i++)
{ /* if not [A-Z] continue, else compare */
if (qword[i-1] < 'A' || qword[i-1] > 'Z') continue;
if (i == 1 && last == qword[i-1]) dcount++;
if (qword[i-1] == qword[i]) dcount++;
}
last = qword[i-1]; /* save last for comparison w/next */
}
printf ("\n sequential duplicated characters [A-Z] : %zu\n\n",
dcount);
return 0;
}
Output/Time with 868789 chars
$ time ./bin/find_dup_digits <dat/d434839c-d-input-d4340a6.txt
sequential duplicated characters [A-Z] : 434893
real 0m0.024s
user 0m0.017s
sys 0m0.005s
Note: the string was actually a string of '0's and '1's run with a modified test of if (qword[i-1] < '0' || qword[i-1] > '9') continue; rather than the test for [A-Z]...continue, but your results with 'A's and 'B's should be virtually identical. 1000000 would still be significantly under .1 seconds. You can play with the RSIZE value to see if there is any benefit to reading a larger (suggested 'power of 2') size of characters. (note: this counts AAAA as 3) Hope this helps.

Resources