I am trying to display a matrix by taking input from a user. Here, the input is a lower triangular matrix and the user may enter the 'x' character which has to be replaced with INT_MAX.
The below program is not working correctly as the output is not matching the expected one.
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int read_int() {
char input[30] = {0};
int number;
for (int i = 0; i < sizeof(input) - 1; i++){
char c = (char)getc(stdin);
if (c == 'x' || c == 'X')
return INT_MAX;
if (c < '0' || '9' < c){
if (i == 0) continue;
input[i] = 0;
return atoi(input);
}
input[i] = c;
}
input[29] = 0;
return atoi(input);
}
int main() {
int N = read_int();
int matrix[N][N];
memset(matrix, 0, N * N * sizeof(int));
for(int i = 0; i < N; ++i){
for(int j = 0; j <= i; ++j){
int distance = read_int();
matrix[i][j] = distance;
matrix[j][i] = distance;
}
}
printf("\n");
for(int i = 0; i < N; ++i){
for(int j = 0; j < N; ++j){
printf("%d\t", matrix[i][j]);
}
printf("\n");
}
printf("\n");
return 0;
}
For input:
3
x 2
x x 2
The Above program prints:
3 2147483647 2147483647
2147483647 32 2147483647
2147483647 2147483647 32
which is not expected
It should be
3 2147483647 2147483647
2147483647 2 2147483647
2147483647 2147483647 2
Update: The answers below, doesn't work for all case [except accepted one]
One such case is -
5
10
50 20
30 5 30
100 20 50 40
10 x x 10 50
it just keeps on taking input
Your logic for skipping whitespace is broken because when you eventually assign a character after skipping position 0, you will always be writing a "wanted" character at position i. That means anything already in position 0 remains.
In your case, it's undefined behavior because input[0] was originally filled with 3 on the first input where no whitespace was skipped, but in subsequent calls to your function it is uninitialized. You then go on to write a 2 into input[1] and thus by pure chance (your array from previous calls has not been overwritten on the stack and the stack is the same), you end up with the string "32" sitting in input.
What you need to do is have some way to count the actual required characters so that you write them into the array at the correct position. One naive approach would be:
int pos = 0;
for(...) {
// other logic...
// Actually write a character we want
input[pos++] = c;
}
Another way that is more like how integer input works is:
int c;
int pos = 0;
while(pos < sizeof(input) - 1 && (c = getc(stdin)) != EOF)
{
if (c == 'x' || c == 'X')
return INT_MAX;
else if (pos == 0 && isspace(c))
continue;
else if (!isdigit(c) && !(pos == 0 && (c == '-' || c == '+')))
break;
input[pos++] = c;
}
input[pos] = '\0';
return atoi(input);
I think the problem is this part of the loop:
if (c < '0' || '9' < c){
if (i == 0) continue;
input[i] = 0;
return atoi(input);
}
If you have entered 3enterx 2 as your input, then the 3 gets read successfully, and the the x gets returned as INT_MAX as intended, but in the next call to read_int, the next character in the input sequence is a space (i.e. c == ' '), and therefore it branches here. Since i == 0 at this point, the loop continues, which means i is incremented to 1, but this also means that input[0] is never changed. Most likely, input[0] contains the same value from the previous call to read_int (3), but in any case, it's undefined behaviour.
As a quick alternative, you can simply change this condition to:
if (c != ' ' && (c < '0' || '9' < c)){
This will mean input[0] will be set to a space character, which atoi will ignore.
An alternative solution could be to read in an entire line at once and tokenise the line.
Related
I'm trying K&R exercise 1-29 and honestly I'm stumped by what my program is doing. Upon inputting a small text file with gcc, the program just runs forever as if there's an infinite loop. Reading through my loops again I can't see any obvious mistakes, so I tried to print different variables to see what's happening, but nothing's printing to the command line - even the variable i from the very first for loop, not even once. Here's my code:
#include <stdio.h>
#define tabStop 10
#define maxInput 1000
int main(){
int i, c, b;
int m, t = 0;
int index, index2;
char input[maxInput];
int nonBlank;
for (i = 0; i<maxInput-1 && (c=getchar()) != EOF; ++i){
if (c != ' '){
input[i] = c;
}
else {
index = i; /*stores location in character array at start of blanks*/
for (b = 0; c == ' '; ++b, ++i); /*counts the number of blanks (b) until the next non-blank character*/
nonBlank = input[i]; /*saves the first seen non-blank character to be re-added later (as getchar() will have taken it in from input and will now stay at that point of the input)*/
index2 = i; /*stores location in character array at end of blanks*/
if (b >= tabStop){ /*if the tab space fits inside the number of blanks, otherwise there is nothing to be done*/
while (t < b){
t += tabStop;
++m;
}
for (int x = 0, i = index; i != index2 && x <= m; ++i, ++x){ /*loops over the number of tabs to be added starting from the first blank in the array found up until the first non-blank*/
input[i] = '\t';
}
while (i != index2){ /*if i did not reach index2 before x surpassed m, there exist remaining spaces to be filled with blanks*/
input[i] = ' ';
++i;
}
}
input[i] = nonBlank; /*puts the first seen non-blank character into place, as getchar() has already covered it and so it wouldn't otherwise be added like other non-blanks*/
}
}
input[i] = '\0';
printf("%s", input);
return 0;
}
Here's the inputted text file:
hello there world
this might be difficult to explain. I am working on a program that takes in a file with numbers in it. the first two numbers are the dimensions of a matrix rows and then columns. the rest of the numbers are the elements of the matrix. what I am having trouble with is that after I created a function to read in a number in a give c style string, the program stops doing anything. It compiles and runs but nothing is ever done, not even printing the first line after main.
proj2.c
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
float readNum(char* buffer, int *pos);
int main(){
char buffer[512];
printf("Enter File Name: ");
//char* fileName = fgets(buffer, sizeof(buffer), stdin);
FILE* file = fopen("matrix.txt", "r");
if(file == NULL){
printf("ERROR COULD NOT OPEN FILE\n");
exit(1);
}
int row = 0;
int col = 0;
int rowcheck = 0;
int colcheck = 0;
int matrixcheck = 0;
while(!feof(file)){
printf("HELLO");
if(fgets(buffer,sizeof(buffer),file) != NULL){
//position of current character
int pos = 0;
//current character
char current;
//loop to determine the dimensions of the matrix
if(colcheck == 0 && rowcheck == 0){
while(colcheck == 0 || rowcheck == 0){
//set current character
current = buffer[pos];
//determine if current character is a number and that the nex character is a space
//for single digit row dimensions
if(current >= '0' && current <= '9' && buffer[pos+1] == ' ' && rowcheck == 0){
row += current - '0';
rowcheck = 1;
}
//if not single digit row dimension add the current character times 10
//and repeat loop to obtain the second digit
else if (buffer[pos+1] >= '0' && buffer[pos+1] <= '9' && rowcheck == 0){
row += (current - '0') * 10;
}
//for columns check if current character is a number and if the next character is space or newline
//and that row has already been checked
else if(current >= '0' && current <= '9' && (buffer[pos+1] == ' ' || buffer[pos+1] == 10) && rowcheck == 1){
col += current - '0';
colcheck = 1;
}
//final check for if columns is double digit so check if next char is a number and that current char is
//not a space
else if(buffer[pos] != ' ' && buffer[pos+1] >= '0' && buffer[pos+1] <= '9' && rowcheck == 1){
col += (current - '0' ) * 10;
}
pos++;
printf("rows: %d cols: %d", row,col);
}
}
//condition to ensure columns and rows have been determined
else if(colcheck == 1 && rowcheck == 1){
//loop to find the elements of the matrix
while(matrixcheck == 0){
current = buffer[pos];
if(buffer[pos + 1] != 10){
if((current >= '0' && current <= '9') || current == '-' || current == '.'){
float num = readNum(buffer, &pos);
printf("number: %f", num);
}
}
}
}
}
}
fclose(file);
}
and readNum.c
#include <stdio.h>
#include <math.h>
float readNum(char* buffer,int *pos){
int negative = 1;
int y = 0;
float number = 0;
if(buffer[*pos] == '-'){
negative = -1;
(*pos)++;
}
while(buffer[*pos + y] >= '0' && buffer[*pos + y] <= '9'){
y++;
}
for(int z = 0; z < y; z++){
number += (buffer[*pos + z] - 48) * pow(10, y - z - 1);
}
*pos += y;
if(buffer[*pos] == '.'){
(*pos)++;
int d = 0;
while(buffer[*pos + d] >= '0' && buffer[*pos + d] <= '9'){
if(buffer[d + *pos] == '.'){
printf("ERROR: multiple decimals in an element");
}
d++;
}
for(int z = 0; z < d; z++){
number += (buffer[z + *pos] - '0') * pow(10, -z - 1);
}
pos += d;
}
return number * negative;
}
commenting out the lines
float num = readNum(buffer, &pos);
printf("number: %f", num);
allows the program to run normally, but uncommenting them it just stops doing anything, in eclipse the console just stays blank running something or other and I terminate it after a bit because nothing is happening, not even the first line is being printed.
this is a sample file that is being read
3 2
56 12 98 25
34.5
45
Thank you in advance
SOLUTION has been found, i'm not sure if everyone understood what exactly is happening in the program. main would not run at all, the first line would not print anything. the solution to this was using fflush(stdout) after the first print statement.
Parsing the file character by character is way to complicated when you are
trying to read floats. Use the function provided by the standard library.
Your code can yield undefined behaviour, because you don't check the boundaries
of buffer, for example:
if(current >= '0' && current <= '9' && buffer[pos+1] == ' ' && rowcheck == 0){
row += current - '0';
rowcheck = 1;
}
You never check if your read the '\0'-terminating byte and keep incrementing
pos, buffer[pos+1] might access beyond the limit. Also I don't understand
how you are really parsing the dimensions. That's why I tell you, don't reinvent
the wheel, use the tools at your disposal.
You say that the dimensions are in the first line, then you can get the
dimension by doing this:
char buffer[512];
if(fgets(buffer, sizeof buffer, file) == NULL)
{
fprintf(stderr, "File is empty\n");
flcose(file);
return 1;
}
size_t cols,rows;
if(fscanf("%zu %zu", &rows, &cols) != 2)
{
fprintf(stderr, "Invalid file format, cannot get columns and rows\n");
fclose(file);
return 1;
}
if(rows == 0 || cols == 0)
{
fprintf(stderr, "Invalid dimension %zux%zu\n", rows, cols);
fclose(file);
return 1;
}
Now, you can parse the file like this:
float matrix[rows][cols] = { 0 };
for(size_t i = 0; i < rows; ++i)
{
if(fgets(buffer, sizeof buffer, file) == NULL)
{
fprintf(stderr, "End of file reached before filling matrix\n");
fclose(file);
return 1;
}
int pos;
char *scan = buffer;
for(size_t j = 0; j < cols; ++j)
{
if(sscanf(scan, "%f%n", matrix[i] + j, &pos) != 1)
{
fprintf(stderr, "Invalid format at line %zu\n", i+2);
break; // continue parsing with the next line
}
scan += pos;
}
}
fclose(file);
printf("matrix[%zu][%zu] = %f\n", rows/2, cols/2, matrix[rows/2][cols/row]);
This code is more robust, because it checks if the functions are working as
intended. If no more lines can be read before the the matrix is filled, then you
can return an error message and end the program. If the lines don't have the
proper format, I ignore that line and the row is filled with 0 while also
printing an error message. If there are more lines than rows, they are ignored
and you would not overflow the buffers. The intentions are also more clear and
it's easier to understand what I'm doing.
Like I said at the beginning, using the function provided by the standard C
library is better than trying to invent the wheel again. Your code is
complicated and hard to read.
Also see why is while(feof) always wrong. It's easier to manage the end
of file when using fgets, because fgets returns NULL when no more data can
be read, either because of an I/O error or because the file reached EOF. That's
why my example above always checks the return value of fgets. Note how I use
%n in the scanf format: %n returns the number of characters consumed thus
far from the input, which is a great info when using sscanf in a loop. I also
check if scanf doesn't return the number of matched elements (note that %n
does not increase the number of matched elements). For more information about
this see the documentation of scanf.
This loop can run forever:
while(buffer[*pos] >= '0' && buffer[*pos] <= '9'){
y++;
}
How can we get out of this loop?:
while(matrixcheck == 0){
current = buffer[pos];
if(buffer[pos + 1] != 10){
if((current >= '0' && current <= '9') || current == '-' || current == '.'){
float num = readNum(buffer, &pos);
printf("number: %f", num);
}
}
}
SOLUTION has been found, i'm not sure if everyone understood what exactly is happening in the program. main would not run at all, the first line would not print anything. the solution to this was using fflush(stdout) after the first print statement.
Let's say I am creating a 3*4 matrix (or a 2D array of 12 elements). So I want user to enter values of elements one by one as a sequence, divided by either spaces/tabs or enter-key. Also, if a value in a sequence is bad (in my case, any non-integer values are bad), I want to ignore it and read next values until I have all 12 of them.
int fill(Matrix * mtx)
{
puts("Start entering numbers. Please note that only integer values will be recorded.");
int temp = 0;
for (int i = 1; i <= mtx -> rows; i++)
{
for (int j = 1; j <= mtx -> cols; j++)
{
scanf(" %d", &temp);
setElement(mtx, i, j, temp);
}
}
return 0;
}
This is my most basic vision of the algorithm; I was wondering about the implementation of this "skip input if bad" condition.
Just started learning C btw, so any kind of advice is hugely appreciated!
You have to check the return value of scanf to be sure whether it scanned the integer input correctly or not. In case it fails due to some bad input - scanf can't take that as input and then you have to make sure that you clear the stdin so that the next calls of scanf don't fail. What you can do is, when scanf returns 0 - consume all characters (using getchar or similar) and do this until you get \n (Considering that user inputs the number each in a line). Illustration would be:
int n; //total number inputs to take.
n = 10;
int num, num_inputs = 0;
while( 1 )
{
while(scanf("%d", &num) != 1)
{
int c;
while ((c = getchar()) != EOF && c != '\n')
;
if(c == EOF){ fprintf(stderr,"Error in input\n"); exit(1)}
}
num_inputs++; // one more int correctly input.
...
if( num_inputs == n )
break;
}
An alternative and better way would be to use strto* functions and then considering the return value of it to understand whether there is any error or not. Illustration would be: (Here we have shown just the case where there is single int input in each line - this can be extended to process multiple int inputs in a line).
char buf[MAXLEN];
int num_inputs = 0;
while(fgets(buf,MAXLEN,stdin)){
char *en;
errno = 0;
long n = strtol(line, &en, 10);
if (errno == 0 && *en== '\0' && n >= INT_MIN && n < INT_MAX)
{
// n is an correctly inputted int
num_inputs++;
}
}
Check the man page for strtol - there is a detailed listing of the erros one might get. Check it.
Check what scanf returns. If not 1 means entered value is not a digit in this case. So discard the data from the stream first before entering next data.
int fill(Matrix * mtx) {
puts("Start entering numbers. Please note that only integer values will be recorded.");
int temp = 0, v;
for (int i = 1; i <= mtx->rows; i++) {
for (int j = 1; j <= mtx->cols; j++) {
v = scanf(" %d", &temp);
if (v != 1) { //if invalid input.
while ( (v = getchar()) != EOF && v != '\n' ); // discard invalid input.
j--; //don't forget to `j--` or else you will skip one position.
}
else { // if correct input.
setElement(mtx, i, j, temp);
}
}
}
return 0;
}
My question is based on a CodeChef problem called Lucky Four.
This is my code:
int count_four() {
int count = 0;
char c = getchar_unlocked();
while (c < '0' || c > '9')
c = getchar_unlocked();
while (c >= '0' && c <= '9') {
if (c == '4')
++count;
c = getchar_unlocked();
}
return count;
}
int main() {
int i, tc;
scanf("%d", &tc);
for (i = 0; i < tc; ++i) {
printf("%d\n", count_four());
}
return 0;
}
Let's say I make a slight change to count_four():
int count_four() {
int count = 0;
char c = getchar_unlocked();
while (c >= '0' && c <= '9') {
if (c == '4')
++count;
c = getchar_unlocked();
}
while (c < '0' || c > '9') // I moved this `while` loop
c = getchar_unlocked();
return count;
}
This is my output after moving the while loop below the other one:
0
3
0
1
0
instead of:
4
0
1
1
0
The input used to test the program:
5
447474
228
6664
40
81
Why is this happening? How do getchar() and getchar_unlocked() work?
getchar_unlocked is just a lower level function to read a byte from the stream without locking it. In a single thread program, it behaves exactly like getchar().
Your change in the count_four function changes its behavior completely.
The original function reads the standard input. It skips non digits, causing an infinite loop at end of file. It then counts digits until it gets a '4'. The count is returned.
Your version reads the input, it skips digits, counting occurrences of '4', it then skips non digits, with the same bug on EOF, and finally returns the count.
This is my solution to the SPOJ problem - The Next Palindrome.
I try to run it, but every time I input a no. like 9XXXXX..., it gives seg. fault, for example -
$ ./a.exe
1
99999
Palin string i++: 99999
Non-Palin String: 99999
Palin string i++: 99999
Non-Palin String: 99999
Palin string i++: 99999
Non-Palin String: 99999
Change string: 99999
9 Palin String: 99099
Palin Str j = 2
Palin Str j-- = 1
9 Palin String: 90099
Palin Str j = 1
Segmentation fault (core dumped)
My code -
#include <stdio.h>
#include <string.h>
#define MAX 1000000
int main(void)
{
unsigned int t;
scanf("%u",&t);
unsigned long int i,j,k,len,change;
char str[MAX];
while(t--){ //For every test case
scanf("%s",str);
i = 0;
change = 0;
len = strlen(str) - 1;
Recheck:
while(i <= (len/2)){ //If the input no. is a palindrome, then don't change it, else change it
if(str[i] != str[len-i]){ //Compare 1st & last digit, then 2nd & 2nd last, so on....., if not same, then...
if(str[i] > str[len-i]){ //if 1st digit > last digit,
str[len-i] = str[i]; //then make last one the same as 1st one
i++;
change++;
}
else if(str[i] < str[len-i]){ //if <, then make the last one same as 1st one,
str[len-i] = str[i]; //but also increment it's left digit,
j = (len-i) - 1; //if required, the next one too, and so on...
while(j >= 0){ //j moves from right to left (digits) in the string
if(str[j] != '9'){
str[j]++;
change++;
break;
}
else if(str[j] == '9'){
str[j] = '0';
if(j == 0){ //If the no. becomes like 9......'\0'
for(k=len+1;k>=0;k--) //and we need to increment, so shift the elements,
str[k+1] = str[k]; //and make the string: 00.......'\0
str[0] = '0'; //Next loop will make str[0] = 1 & break.
len++;
j++;
}
change++;
}
printf("\n9 Non-Palin String: %s",str);
j--;
}
if(j <= i) //if the change reaches even before from where we compared(in 1st half, that is, i),
i = j; //then change i to j, so that the no. can be checked again from j, as changes are till j.
else
i++;
}
}
else if(str[i] == str[len-i]){ //No change to a palindrome
printf("\nPalin string i++: %s",str);
i++;
}
printf("\nNon-Palin String: %s",str);
}
if(change==0){ //change == 0 means that the no. was already a palindrome
printf("\nChange string: %s",str); //so we have to find the next no. which is a palindrome
if(len%2)
j = (len/2) + 1;
else
j = len/2;
if(str[j] == '9'){ //So, if the mid char(s) is/are 9 then change the no. as we did before
while(j >= 0){
if(str[j] != '9'){
str[j]++;
change++;
break;
}
else if(str[j] == '9'){
str[j] = '0';
if(j == 0){
for(k=len+1;k>=0;k--)
str[k+1] = str[k];
str[0] = '0';
len++;
j++;
printf("\nIncrement string");
}
change++;
}
printf("\n9 Palin String: %s",str);
printf("\nPalin Str j = %lu",j);
j -= 1;
printf("\nPalin Str j-- = %lu",j);
}
printf("\nPalin to Recheck: %s",str);
i = j;
goto Recheck;
}
else{ //else, just increment the mid char/s
if(len%2){
str[j]++;
str[j-1]++;
}
else{
str[j]++;
}
}
}
printf("\n%s",str);
}
return 0;
}
I've added comments to understand the code.
For every no., 9, 99, 999, etc. it gives segmentation fault error.
It seems odd to write an answer to my own question, but still...
The problem with the solution is that the variable k is an unsigned int, so k is never < 0, hence the infinite loop.
Thanks to pm100 & Weather Vane for their help.
Not a full answer but too much for a comment.
What do you mean by "stdin input buffer"? Your typing goes into a system buffer until you press "Enter" at which point the contents are transferred to your array str by scanf(). The stream used is a predefined system stream call stdin. You can use the similar file function fscanf(stdin,"%s",str); but scanf() is more convenient (and not a very desirable method for a string anyway). However, it is very unlikely that the system buffer can hold 1 million characters, so I suggest you build the string yourself, something like this:
#include <stdio.h>
#include <conio.h>
#define MAX 1000000
int main(void)
{
char str [MAX] = ""; // initialise string to the empty string
int str_len = 0; // length (and index into) str
int c;
do {
c = getch (); // gets a char but the type returned is int
printf("%c", c);
if (c != 13)
str [str_len++] = c; // insert in array
}
while (c != 13 && str_len < MAX-1);
str [str_len] = 0; // terminate array
printf("\n%s\n", str);
printf("Length %d\n", str_len);
return 0;
}