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.
Related
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.
I want to write a program which reads a line of input from the user, in the following format: <Name>,<Age>,<City>
The Name can contain English letters, spaces and - only.
The Age must be an integer between 18 to 120.
The City must contain English letters and - only.
Each of them can be of size 49.
I want to store the information and print an informative error will be printed for bad input.
My code is the following:
char str[150];
char input[3][50] = { 0 };
int num = 0;
if (fgets(str, 150, stdin) != NULL) {
num = sscanf(str, "%[a-zA-Z -],%[0-9],%[a-zA-Z-]", input[0], input[1], input[2]);
}
if (num < 3) {
printf("ERROR\n");
}
The problem is that an error will not be printed for an input such as Name1$#,20,NY, Best,19,Rome123, or Best,100,Paris1$, where the city is in wrong format (with trailing characters). There is any way to solve it using sscanf?
You can use sscanf() and character classes for your purpose but there are small problems with your format string:
A-Z assumes ASCII encoding or at least an encoding where letters are contiguous.
a trailing - has a special meaning, put the dash in first position to match a dash explicitly.
there is no length prefix, so a name or city longer than 49 characters will overflow the destination array.
Rather than using fgets(), you should read the line mannually to detect overlong lines.
You can add an extra %c to check for extra characters at the end of the line. Storing the converted value is not required if you don't intend to use the field values, but you must convert the number to check if its value is in the requested range:
char str[150];
char name[50];
char city[50];
char agestr[4];
size_t i;
int c, age, pos, n;
for (i = 0; (c = getchar()) != EOF && c != '\n'; i++) {
if (i < sizeof(str) - 1)
str[i] = (char)c;
}
if (c == EOF && i == 0) {
printf("end of file\n");
return -1;
}
if (i >= sizeof(str)) {
printf("line too long\n");
return 0;
}
str[i] = '\0';
pos = 0;
/* validate the name */
if (sscanf(str + pos, "%49[-a-zA-Z ]%n", name, &n) != 1 || str[pos + n] != ',') {
printf("invalid name\n");
return 0;
}
pos += n + 1;
/* validate the age */
if (str[pos] == '0' || sscanf(str + pos, "%3[0-9]%n", agestr, &n) != 1 || str[pos + n] != ',') {
printf("invalid age\n");
return 0;
}
age = atoi(agestr);
if (age < 18 || age > 120) {
printf("age out of range: %d\n", age);
return 0;
}
pos += n + 1;
/* validate the city */
if (sscanf(str + pos, "%49[-a-zA-Z]%n", city, &n) != 1 || str[pos + n] != '\0') {
printf("invalid city\n");
return 0;
}
/* Input was validated... proceed */
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;
}
I am trying to write a piece of C code that takes a sentence and returns all the palindromes in that sentence, each in a new line. For example, the sentence "I like to race a civic racecar" would return:
civic
racecar
I've tried to use some debugging software (lldb, as I'm a mac user), but found it a bit confusing. The code below is what I have written. It's returning a segmentation fault, and I'm having trouble identifying it within my program.
int is_palin(char c[], int length)
{
int front = 0;
int back = length - 1; /* account for length starting at 0 */
if (length % 2 == 0){ /* check for even palindromes */
int middle = (length /2) -1 ;
while (front< middle + 1){
if (c[front] != c[back]){
return 0;}
front = front + 1;
back = back -1;
}
}
else { /* check for odd palindromes */
int middle = ((back - 2) / 2 ) + 1;
while (front != middle){
if (c[front] != c[back]){
return 0;}
front = front + 1;
back = back -1;}
}
return 1;
}
int is_delimiting_char(char ch)
{
if(ch == ' ') //White space
return 1;
else if(ch == ',') //Comma
return 1;
else if(ch == '.') //Period
return 1;
else if(ch == '!') //Exclamation
return 1;
else if(ch == '?') //Question mark
return 1;
else if(ch == '_') //Underscore
return 1;
else if(ch == '-') //Hyphen
return 1;
else if(ch == '(') //Opening parentheses
return 1;
else if(ch == ')') //Closing parentheses
return 1;
else if(ch == '\n') //Newline (the input ends with it)
return 1;
else
return 0;
}
/////////////////////////////////////////////
//---------------------------------------------------------------------------
// MAIN function
//---------------------------------------------------------------------------
int main (int argc, char** argv) {
char input_sentence[100];
int i=0;
char current_char;
int delimiting_char;
char word[20];
int word_length;
int have_palindrome = 0;
/////////////////////////////////////////////
/////////////////////////////////////////////
/* Infinite loop
* Asks for input sentence and prints the palindromes in it
* Terminated by user (e.g. CTRL+C)
*/
while(1) {
i=0;
print_char('\n');
print_string("input: ");
/* Read the input sentence.
* It is just a sequence of character terminated by a new line (\n) character.
*/
do {
current_char=read_char();
input_sentence[i]=current_char;
i++;
} while (current_char != '\n');
/////////////////////////////////////////////
print_string("output:\n");
int char_index = 0;
for(int k=0; k<i; k++) {
palin = 1;
current_char = input_sentence[k];
delimiting_char = is_delimiting_char(current_char);
if(delimiting_char) {
if (char_index > 0) { //Avoids printing a blank line in case of consecutive delimiting characters.
word[char_index++] = '\n'; //Puts an newline character so the next word in printed in a new line.
word_length = word_length + 1;
if (is_palin(word, word_length) && word_length > 1){
have_palindrome = 1;
for(int j=0; j<char_index; j++) {
print_char(word[j]);
}
word_length = 0;
char_index = 0;
}
} }
else {
word[char_index++] = current_char;
word_length = word_length + 1;
}
}
if (have_palindrome == 0){
print_string("Sorry! No palindromes found!"); }
}
return 0;
}
Also wondering if anyone has good videos or sites for learnign how to use lldb, when one has never used anything of the sort before. Thanks!
There are several things wrong here:
word_length is uninitialised at first use, so statements like word_length = word_length + 1 lead to undefined behaviour. In fact, you have two different variables, char_index and word_length, that should always have the same value. Instead of going through the hassle to keep them in sync, use just one variable.
You reset both char_index and word_length to zero only if a palindrome was found. You should reset if after every word, of course.
The line palin = 1; is probably a leftover from older code. You should also reset have_palindrome after each line. In general, you should take more care when defining variables.
By adding a newline to your word you make printing a bit easier, but you will never find a palindrome, because the newline at the end is taken into account when checking for the palindrome.
Your code for reading with read_char, which is probably an alias to getchar, needs to check for the end of input.
You don't need to distinguish between even and odd sized palindromes. Just make the condition that front < back and be done with it. The middle character of an odd sized palindrome doesn't matter. (That's not an error, your code is just needlessly complicated.)
I've been having some problems with this code below...
The main idea of the code is to read line by line and convert chars strings into floats and save the floats in a array called nfloat.
The input is a .txt containing this: n = the number of strings, in this case n = 3
3
[9.3,1.2,87.9]
[1.0,1.0]
[0.0,0.0,1.0]
The first number, 3 is the number of vectors as we can see in the image, but that number isn't static, the input can be 5 or 7, etc instead of 3.
So far, I've started doing the following, (for only 1 vector case) but the code has some memory errors I think:
int main(){
int n; //number of string, comes in the input
scanf("%d\n", &n);
char *line = NULL;
size_t len = 0;
ssize_t read;
read = getline(&line,&len,stdin); //here the program assigns memory for the 1st string
int numsvector = NumsVector(line, read);//calculate the amount of numbers in the strng
float nfloat[numsvector];
int i;
for (i = 0; i < numsvector; ++i)
{
if(numsvector == 1){
sscanf(line, "[%f]", &nfloat[i]);
}
else if(numsvector == 2){
if(i == 0) {
sscanf(line, "[%f,", &nfloat[i]);
printf("%f ", nfloat[i]);
}
else if(i == (numsvector-1)){
sscanf((line+1), "%f]", &nfloat[i]);
printf("%f\n", nfloat[i]);
}
}
else { //Here is where I think the problems are
if(i == 0) {
sscanf(line, "[%f,", &nfloat[i]);
printf("%f\n", nfloat[i]);
}
else if(i == (numsvector-1)) {
sscanf((line+1+(4*i)), "%f]", &nfloat[i]);
printf("%f\n", nfloat[i]);
}
else {
sscanf((line+1+(4*i)), "%f,", &nfloat[i]);
printf("%f\n", nfloat[i]);
}
}
}
Well, the problems come with the sscanf instructions I think, in the case of a string with two floats or one, the code works fine but in the case of 3 or more floats, the code doesn't work well and I can't understand why...
Here I attach the function too, but It seems to be correct... the focus of the problem remains on the main.
int NumsVector(char *linea, ssize_t size){
int numsvector = 1; //minimum value = 1
int n;
for(n = 2; n<= size; n++){
if (linea[n] != '[' && linea[n] != ']'){
if(linea[n] == 44){
numsvector = numsvector + 1;
}
}
}
return numsvector;
}
Please could someone help me understand where is the problem?
Ok - if you replace your current for loop with this, your nfloat array should end up with the right numbers in it.
/* Replaces the end ] with a , */
line[strlen(line) - 1] = ',';
/* creates a new pointer, pointing after the first [ in the original string */
char *p = line + 1;
do
{
/* grabs up to the next comma as a float */
sscanf(p, "%f,", &nfloat[i]);
/* prints the float it's just grabbed to 2 dp */
printf("%.2f\n",nfloat[i]);
/* moves pointer forward to next comma */
while (*(p++) != ',');
}
while (++i < numsvector); /* stops when you've got the expected number */