fscanf results in a segmentation fault - c

void RdImage(FILE *fpi, char Image1[MAXROW][MAXCOL], int Nrows, int Ncols) {
int i = 0, j = 0, temp;
while (!feof(fpi)) {
if (i % Nrows == 0) {
i = 0;
j++;
}
**fscanf(fpi, "%d", temp);**
if (temp == 1) {
Image1[i][j] == AP;
} else {
Image1[i][j] == PL;
}
i++;
}
}
The line I've inclosed in asterisks is giving me a segmentation fault. The file is definitely NOT empty. I've used the same line twice elsewhere in my program and it doesn't behave this way there.

temp is an integer; you have to pass its address:
fscanf(fpi, "%d", &temp);
Turn on warnings in your compiler to catch bugs like this.

As per C99 Std
7.19.6.2 The fscanf function
%d
Matches an optionally signed decimal integer, whose format is the same as
expected for the subject sequence of the strtol function with the value 10
for the base argument.
The corresponding argument shall be a pointer to signed integer.
so
fscanf(fpi, "%d", &temp); //Here Address of temp is passed.
is the correct one.

please use &temp instead of temp in fscanf
fscanf(fpi, "%d", &temp);

Related

fscanf-- trying to scan txt file of ints, fscanf only reads 1s

I'm trying to use fscanf to read a file containing 25 ints and store them in memory. However, it appears that for the first 12 values, instead of scanning the actual int in the file fscanf is always showing up as 1. The 13th value shows up as -1, and then the while loop in the code below terminates. Any idea why this might be? Thanks for your help.
#include <stdio.h>
#include <stdlib.h>
#include "matrix.h"
#define ROWS 5
#define COLS 5
void load_file(FILE* file, int** p);
int main()
{
FILE* f1;
f1 = fopen("twenty-five-ints.txt", "r");
int p=0;
int* matrix = &p;
load_file(f1, &matrix);
}
void load_file(FILE* file, int** p) {
*p = malloc(25*sizeof(int));
int number = 0;
int i = 0;
while (fscanf(file, "%d", &number) != EOF) {
*(*p + i) = fscanf(file, "%d", &number);
printf("%d ", *(*p + i));
i++;
}
printf("\n");
}
The printf statement inside the while loop prints out 12 ones separated by spaces, followed by a -1.
There are two things to mention.
Remove one fscanf() call. Othersise, you'll end up losing every alternative value scanned.
fscanf() does not return the scanned value. In case a macth is found, it stores the scanned value in the supplied argument (&number). Use the argument to get the scanned value. You can make use of the return value to check for the suucess os the call to fscanf().
Quoting the man page, (emphasis mine)
The scanf() family of functions scans input according to format as described below. This format may contain conversion specifications; the results from such conversions, if any, are stored in the locations pointed to by the pointer arguments that follow format. [...]
You should not fscanf() twice and you should compare fscanf() to the number of expected fields to be scanned.
while ((i < 25) && (fscanf(file, "%d", (*p + i)) == 1))
printf("%d ", *(*p + i++));
Also, fscanf() does not return the scanned value, what would you expect it to return in this case?
fscanf(file, "%s%d%", &string, &integer);
Aditionally Consider:
Using index notation to dereference the pointer.
Using an aditional pointer to avoid confusion.
Checking the return value from malloc()
void
load_file(FILE *file, int **data)
{
int *pointer;
size_t i;
*data = NULL; // So you can test this after the call to the function
pointer = malloc(25 * sizeof(**data));
/* ^ if this is a constant, this doesn't make a lot of sense */
/* because you can use an array instead. */
if (pointer == NULL)
return;
for (i = 0 ; ((i < 25) && (fscanf(file, "%d", &pointer[i]) == 1) ; ++i)
printf("%d ", pointer[i]);
printf("\n");
*data = pointer;
}
In my opinion, this function is poorly designed. You can't verify if the read values where in fact 25, nor can you specify that anywhere. If you want a function to read a given number of integers with a maximum try this
size_t
load_file(FILE *file, int **data, size_t maximum)
{
int *pointer;
size_t i;
*data = NULL; // So you can test this after the call to the function
pointer = malloc(maximum * sizeof(**data));
if (pointer == NULL)
return;
for (i = 0 ; ((i < maximum) && (fscanf(file, "%d", &pointer[i]) == 1) ; ++i)
;
*data = pointer;
return i;
}
With this function, you can do this
int *data;
// We assume that FILE * is a valid stream
size_t count = load_file(file, &data, 25);
if (data != NULL)
{
for (size_t i = 0 ; i < count ; ++i)
fprintf(stdout, "%d ", data[i]);
fputc('\n', stdout);
free(data);
}

scanf confusion with type error

I just make a program to guess some random pairs in an array,if guess right, delete this pair.
I met a problem that I can only type integer number.Everytime I tried to type like * ,the program will crash. I use a condition like:
if (scanf("%d",&temp)==1)
to try to fix my problem, but it really does'nt work.
here is my code and please give me some help:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
int r[4]; //random
int s[8]; //store
char c[8]; //cover
int g[8]; //guess
int i;
int round=0;
int left = 4;
int point = 0;
int clear_index[2];
int temp;
// generate random number
for (i=0;i<4;i++)
{
r[i] = (rand()%10)+1;
s[i] = r[i];
s[i+4] = r[i];
}
// show the default number
printf("[show] ");
for (i=0;i<8;i++)
{
printf("%d ",s[i]);
c[i] = '*';
}
printf("\n");
while(left>0)
{
// print left
printf("[cover] ");
for (i=0;i<8;i++)
printf("%c ",c[i]);
printf("\n");
//guess
printf("[guess] ");
for(i=0;i<8;i++)
{
if (scanf("%d",&temp)==1)
g[i] = temp;
if (g[i] == s[i])
{
printf("v\n");
clear_index[point] = i;
point++;
}
}
if (point == 2)
{
for (i=0;i<2;i++)
c[clear_index[i]]=' ';
left-=1;
point = 0;
}
round+=1;
//left-=1;
}
printf("you won in %d round",round);
}
You get the segmentation fault, because, in case, you did not enter an integer, scanf will not return 1, and then, using g[i] will invoke undefined behavior.
FWIW, g is a local automatic array variable, and unless initialized explicitly, will have indeterminate value. Attempt to read the value will invoke the UB.
Solution:
Always initialize the local variables.
In case scanf() fails, you need to eat up the invalid input using some loop like while (getchar != '\n'); before you proceed to take the next input.
You are reading a number but the user can place a digit. To prevent this you can use the function atoi() from the library stdlib.h. It converts a string to a integer, if the integer is just number digits, it'll convert it to a integer. If it is a character it will return 0. So you just need to prevent the occurrence of a 0 after the atoi() function is called.

Adding incremental integers to end of string in C

need some help with sprintf. I keep running into the error 'sprintf' makes pointer from integer without a cast.
a was declared in the main function to be char a[1000]
int
next_statement(char *a, int n) {
int c, i,z;
for (i=0; i < n && (c = getchar()) != EOF; i++) {
if (c == CHAR_SEMI) {
consume_char('\n');
break;
}
a[i] = c;
}
for(z=0; z<n;z++){
if (c == CHAR_SEMI) {
a[i-3] = 'x';
sprintf(a[i-2], "%d", z);
a[i-1] = ';';
a[i] = '\0';
return i; /* index when ; was read, so the length of saved. */
}
else if (i >= n) {
printf("%s Line too long.\n", ERROR_PREFIX);
exit(EXIT_FAILURE);
}
}
return 0;
}
In this line a[i-2] is single character. It will not represent the character pointer.
sprintf(a[i-2], "%d", z);
so you can try like this,
sprintf(&a[i-2], "%d", z);
From the man page of sprintf
int sprintf(char *str, const char *format, ...);
It requires the first argument as a character pointer.
As you've written, a[i-2] denotes the char, not a char *, as required by sprintf() as it's first parameter. You need to supply the pointer for the string to write on.
[] is the Array subscripting operator. You need not use that operator. So, instead of
sprintf(a[i-2], "%d", z);
you can use like
sprintf( (a+i-2), "%d", z);
sprintf() takes first argument as a char * type, But your mention here as a[i-2] character type,
So you can give like this
sprintf( ((a+i)-2) ,"%d", z);

fscanf can't read the first integer of my file input in C but reads the rest

My program needs to read input from a file. The file has a format "int int int" and then some asterisks to indicate that you need to stop reading there. I want to store them in an array of struct and I did. But it seems like my program can't read the very first integer of the input file. I checked it with printf and I can't do anything about it. Help please. Here's the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct points{
int i;
int x;
int y;
};
int main(){
int lines = 0;
char c, e;
int i, j, x ,y, a, b, temp ;
FILE *fp;
fp = fopen("input.txt", "r");
if (fp != NULL){
while ((e = fgetc(fp)) != '*'){
if (c == '\n'){
lines++;
}
fscanf(fp, "%d%d%d", &i, &x, &y);
struct points pt[lines];
for (j = 0; j <= lines; j++){
pt[j].i = i;
pt[j].x = x;
pt[j].y = y;
printf("%d ", pt[j].i);
}
for (a = 0; a<=lines; a++){
for (b = a + 1; b <= lines; b++){
if (pt[a].x > pt[b].x){
temp = pt[a].x;
pt[a].x = pt[b].x;
pt[b].x = temp;
}
}
}
}
}
else{
printf("Cannot open File!\n");
}
printf("lines = %d\n", lines);
return 0;
}
Your code:
while ((e = fgetc(fp)) != '*') {
if (c == '\n'){
lines++;
}
fscanf(fp, "%d%d%d", &i, &x, &y);
will read the first character and throw it away if it is NOT an asterisk, and will then attempt to read 3 integers AFTER that first character it threw away. If that first character was a digit, then it will look like you 'lost' (part of) the first number.
You also have the problem that you seem to be trying to read the values into a block-local array pt that exists for a single iteration of the while loop (so its recreated with no (garbage) contents each iteration), and then you want to use it after the loop where it is out of scope (so this code won't compile).
What you want is probably something more like:
#define MAX_POINTS 100
struct points pt[MAX_POINTS];
int i = 0;
while (i < MAX_POINTS && 3 == fscanf(fp, "%d%d%d", &pt[i].i, &pt[i].x, &pt[i].y)) {
printf("%d ", pt[i].i);
i++;
}
for (int a = 0; a <= i; a++) {
for (int b = a+1; b <= i; b++) {
:
Note that this reads integers up until it finds something that doesn't look like an integer (such as an asterisk, but could be anything else, including an end-of-file), rather than reading until it finds an asterisk. If you want to read until you see an asterisk, you need to decide what to do with anything that is neither an asterisk or an integer.
Edit
for your alternate question of how to read numbers up to *** and then read more numbers after them (and possibly more stars), you could use something like:
int val;
char buffer[20];
do {
/* start of a group */
while (1 == fscanf(fp, "%d", &val)) {
/* read an integer within a group */
}
/* fp is at EOF or something not an integer. */
/* so read it and loop if its '***' */
} while (1 == fscanf(" %19[*]", &buf) && !strcmp(buf, "***"));
Have you tried using the format string "%d %d %d" instead of "%d%d%d" (i.e. with spaces)?
Also, there are several other problems I see:
You use a while loop to find the first '*' in the line, but then you ask fscanf to parse 3 ints starting at that location. It may not be able to find an int by looking at a '*'...
You also declare the variable struct points pt[lines]; in the middle of a block; that is not valid C syntax.
Once you fix these things, the problem may be fixed.

pulling values from pointers in a loop

getLine is a function that gets a line, I'm trying to combine lines together outside the getLine function. When ever I try doing this in a loop it messes up the output. I bet it has to do with the pointers, but I have spend many hours trying to figure it out.
int num;
int matrix[370];
i=1;
j=0;
while(*(point=getLine(infile)) != -2){
n[j]=*point;
if(n[0] != n[j]){
printf("matrix dim error 1");
break;
}
while (i<=n[j]){
matrix[i+(3*j)] = *(point+(i+(3*j)));
i++;
printf("%d", matrix[i+(3*j)]);
}
printf("%d %d %d\n", matrix[1],matrix[2],matrix[3]);
j++;
}
fclose( infile );
}
int *getLine(FILE *infile){
int l=0;
int line[7];
int i=1;
int *point;
while ((l=getNum(infile)) != -1){
if(l==EOF){
line[0]=EOF;
point = &line[0];
return(point);
}
line[i]=l;
i++;
}
if(i==1){
line[0]=-2;
point = &line[0];
return(point);
}
line[0]=(i-1); //stores the length of the line in first space
printf("%d %d %d\n",line[1],line[2],line[3]);
point = &line[0];
printf("%d\n",*point);
return(point);
}
int getNum(FILE *infile) {
int c=0;
int value=0;
while ((c=fgetc(infile)) != '\n') {
if(c==EOF){
return(EOF);
}
if((c==32)||(c==13)){
if(value != 0){ //Making sure a number has been gotten
//printf("%d\n\n", value);
return(value);
}
//otherwise keep getting characters
}
else if ((c<=47)||(c>=58)){
printf("incorrect number input %d\n", c);
exit(1);
}
else {
value = (10*value) + (c - '0');
}
}
return(-1);//flags that the end of line has been hit
}
There is one problem:
int *getLine(FILE *infile){
int line[7];
int *point;
point = &line[0];
return(point);
}
You return a pointer to a local variable. It becomes invalid when you return from the function. You could allocate it instead on the heap, or let the caller provide it as an argument.
Instead of
while (i<=n[j]){
didn't you mean
while (i<=n[j][0]){
More Edit: That's actually ok, i overlook the * in the assignment.
Edit: Some more things:
there is no check that the range of int is not exceeded in getNum
there is no check in getLine that more than 7 values are read (which would blow int line[7]
the matrix calculation in my opinion assumes that there are 3 values read, getLine can deliver up to 7
matrix[i+(3*j)] = *(point+(i+(3*j))); ?? point is only 7 int big!!! so for the second value it will read beyond defined data. Shouldn't it read matrix[i+(3*j)] = point[i];
hth
Mario
BTW: I strongly recommend:
resort to std-lib functions
better naming (i and j in the same source are strongly discouraged)

Resources