Error array size - c

I need to assign a character array containing 300000 data which are fetched from a file Numbers.dat containing 200,0000 numbers arranged in a column format(its a huge data file). The operation is to fetch in data from this file and store it in an array in blocks of 300000 so that these 300000 numbers are again stored in different files.This operation is performed for two files which are therefore subsets of the Numbers are of form
-0.98765
-0.124567
etc
But I am getting TWo errors : First is syntactic error saying the array size is too long and the other is logical error. How to resolve this. The code is as under provided by Gunner in How to read blocks of numbers from a text file in Cbut not working when used for this case
#include <stdio.h>
#include<stdlib.h>
# include <conio.h>
# include <dos.h>
# include <math.h>
void main()
{ FILE *fpt1,*fpt2,*fpt;
fp=fopen("numbers.dat","r");
fpt1=fopen("subset1.dat","w");
fpt2=fopen("subset2.dat","w");
int index=0;
char anum[300000]; //this is the reason for the first syntactic error :Array size too large
// since we are not calculating, we can store numbers as string
while( fscanf(fp,"%s",anum) == 1 )
{
if(index==0)
{
// select proper output file based on index.
fprintf(fpt1,"%s",anum);
index++; }
if(index ==300000)
{
fprintf(fpt2,"%s",anum);
index++; }
}
fclose(fp);
fclose(fpt1);
fclose(fpt2);
}
The logical error is that only one number is being written in file subset1 and subset2 even when I reduce the size to 300 blocks of data.

Your compiler doesn't support static arrays with such a capacity. Use a compiler that allows this(most modern compilers do).
You can also try to allocate the memory dynamically.

Related

Storing integers as an array by reading size of array and the elemnts of the array in a single line

I am trying to create an array from the integers that a user inputs. They must be inputted on the same line, e.g. 5 1 2 3 1 6. The number of integers can be any amount.
However, the first number + 1 determines the size of the array. E.g. if the user inputs the number 5 first, it must be followed by 5 other random integers thus making the length of the array 6. I'm getting confused on how to do this because there is so much user input. Thanks in advance!
Here is my code so far, though i don't think it'll be much help:
#include <stdio.h>
int main(void) {
int arr_days[13];
int i = 0;
printf(" ");
while(i < 13) {
scanf("%d", &arr_days[i]);
i = i + 1;
}
printf("%d", arr_days[0]);
return 0;
}
You weren't too far off, you just need to allocate the buffer dynamically and read the first number separately so that you know how much space and how many loops to perform.
You might also want to check if arr_days is NULL after the malloc to protect against 'out of memory' problems.
#include <stdio.h>
int main(void) {
int* arr_days;
int i = 0;
int n;
printf(" ");
// get first number to find out how many more to expect
scanf("%d", &n);
// create memory space to store them
arr_days = malloc(n * sizeof(int));
while(i < n) {
scanf("%d", &arr_days[i]);
i = i + 1;
}
printf("%d", arr_days[0]);
return 0;
}
EDIT: I see from some comments further down that there is some confusion about scanf. This command will trigger an input request if there is no input pending, then it will process any pending input. So when you type in a bunch of numbers in response to a scanf input prompt (or pipe a text file with those numbers in to the program) each invocation of scanf("%d",...) will only extract the next single integer, leaving the rest of the input still available. If you think of it like the string is a file, scanf is reading from that file and leaving the file pointer at the end of the bit it just read ready for the next invocation to read the next bit... (which is exactly what happens if you pipe a text file!)
First you would need to get the number so that you know how many numbers to read and how big to allocate the array.
int num;
scanf("%d", &num);
int *arr = malloc(num * sizeof(int));
Second, read each of the numbers one by one.
int I;
for (I = 0; I < num; I++) {
scanf("%d", &arr[I]);
}
This shows as an example of how to do the task, you will need to take care of check scanf's result to make sure the input was successful, and check malloc for allocation too.
If you want to set the array size based on an input then the input has to be read first. What you want is to input all numbers in a line(including size of the array), which means the numbers will be read after the end of line only(after pressing [Enter]). This case is not possible with static arrays.
You can't read all the inputs i.e. array size & integers to be put in it on the same line & build an static array. But you may build a dynamic array by implementing a dynamic array and taking all inputs in the same line.
A dynamic array is a re-sizable array or array list with random
access, variable-size list data structure that allows elements to be
added or removed.
A static array required the size of the array to be created so
that that memory could be allocated before array elements can be added
to it.
All this being said,
if your array size has an upper-bound size(i.e. the maximum number of elements which you would accept is set) then you may create a static array of the maximum size and read you inputs into it.
int arr[MAX_ARRAY_SIZE ASSUMED];
This allocates an array of size MAX_SIZE_ASSUMED which means all your inputs maybe stored in the static array. But this is a bad way to implement as MAX_SIZE_ASSUMED is always the size of the array even when you may just enter one element into the array.

C: fread does not read the full block

Here's my code so far:
#include <stdio.h>
#include <stdint.h>
#define N_DET 432
#define N_PROJ 500
int readSinogram(uint16_t mess[],char filename[], int sample){
//init
FILE *fp;
int i;
//open file
fp=fopen(filename,"r");
//read sinogram
fseek(fp,sizeof(uint16_t)*N_DET*N_PROJ*sample*2,SEEK_SET); //move pointer
fread(mess,sizeof(uint16_t),N_DET*N_PROJ,fp); //read sinogram
return 0;
};
int main()
{
uint16_t mess[N_DET*N_PROJ];
char filename[]="C:\\Path\\MyFile.fxc";
double curr;
int i,DET,PROJ;
readSinogram(mess,filename,0); //read the data
printf("\nDET?"); //ask for input
scanf("%u", &DET);
printf("\nPROJ?");
scanf("%u", &PROJ);
curr=mess[DET+N_DET*PROJ]; //get the data
printf("Data: %f",curr); //print the data
return 0;
}
This reads in the .fxc file, which is just a binary file containing uint16_t formatted numbers. "readSinogram" reads one data set which contains N_DET*N_PROJ numbers. (The pointer is moved by twice the block size, because there are alternating blocks of two measurements in the file.)
After reading it, one can put in a DET and PROJ and have a look at the data at this point.
So far, everything works fine. The data is correct for a certain data range but when asking for too big DET and/or PROJ the data is incorrect.
I do have the same file read in in Matlab and can confirm that the data in it is fine.
To be more exact: every index above [DET+N_DET*PROJ] > 248835 will return 52428 instead of the correct value (ranging from 0 to 4088). The values up to those work fine. So there's got to be something wrong with the "mess" array above that index, I guess.
What am I doing wrong? Thanks in advance!
you need allocate a larger array to get to index value greater than 248835
currently you have the following defines
#define N_DET 432
#define N_PROJ 500
which leads to the array size of 432*500 = 216000
now if your indexing the array at value 248835 248835 > 216000 you would cause to access the memory out of the allocated memory for the array which would lead to undefined behavior. What you need is a bigger size array which can accommodate more than 248835 entries. a simple #define N_DET 500 would do that, but you have to make sure that is the requirement. A basic index check would be helpful to avoid having a out of range problem something on the lines of
#define MAX_RANGE 500*500
if((DET+N_DET*PROJ) < MAX_RANGE)
curr=mess[DET+N_DET*PROJ]; //get the data
else
//error handling
you also need error handling in fopen fseek and check the return for fread plus optionally you can close the opened file discriptor by close(fd)

Is it possible to include loop counter in name of array when declaring it? (in C)

I have this loop which creates a certain number of array depending on a value input by the user. I want to include the counter of the array at the end of the array name such that it is: array1[], array2[], array3[] and so on, one for each iteration. Would this be possible? We have just started learning C now at university so I don't know much about it yet. I tried the following:
#include <stdio.h>
int main(void)
{
//Variables
int i, columns, column_size;
//Read input
printf("Input number of columns:\n");
scanf("%d", &columns)
//Loop to create arrays
for (i=1; i<=columns; i=i+step)
{
//Read column size
scanf("%d", &column_size);
//Create an array of given size for this column
int column+"i"+[column_size];
}
return 0;
}
I want to include the counter of the array at the end of the array name such that it is: array1[], array2[], array3[] and so on, one for each iteration
That is not possible. C is a compiled language, meaning that a program (the compiler) creates the program at one point in time and the program eats user-input at a different point in time.
Even the names of the "variables" might vanish after compilation, they are not needed to execute the program.
int a;
All this does is to tell the compiler that you, the programmer need 32bits of space to store something. If you want to store something there later on, you use the name "a":
a = 42;
The compiler calculates the offset to your current location in RAM and stores the "42" at that address. At runtime the used "names" are completely irrelevant, there is no lookup for the right place involved.
This is the difference to an "interpreted language" like Python.

SIGSEGV error keeps showing up

this error keeps on appearing for every program i try to submit on spoj.pl
In the given code i need to find prime numbers between m - n for t no. of test cases .
problem statement:http://www.spoj.com/problems/PRIME1/
the same error is appearing ..
can anyone plss tell me why this error shows up again nd again ..
here's my code
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
int main()
{
int t;
scanf("%d",&t);
int *m,*n;
m=(int *)malloc(sizeof(int)*t);
n=(int *)malloc(sizeof(int)*t);
int i=0;
while(i<t)
{
scanf("%d%d",(m+i),(n+i));
i++;
}
i=0;
while(i<t)
{
long long int *list,j,k;
list=((long long int*)malloc(sizeof(long long int)*(n[i]+1)));
list[0]=list[1]=0;
for(j=2;j<=*(n+i);j++)
{
*(list+j)=1;
}
float l=sqrt(*(n+i)+1);
//int l=sqrt(*(n+i)+1);
for(j=2;j<=l;j++)
{
if(*(list+j)==1)
{
//printf("\n%ld",j);
for(k=j*j;k<=*(n+i);k=k+j)
*(list+k)=0;
}
}
for(j=m[i];j<=n[i];j++)
{
if(*(list+j)==1)
{
printf("\n%ld",j);
}
}
printf("\n");
free(list);
i++;
}
free(m);
free(n);
return 0;
}
First -- you should not cast malloc -- it can cause unexpected errors.
Second, there's no validation that you allocated the memory you need. There are three different places you're asking for memory and never look to see if malloc returned a NULL result... if t and/or (n[i]+1) is sufficiently large, malloc() may be unable to get a chunk of memory big enough to satisfy the request, in which case you're trying to assign to a NULL pointer and you get a SIGSEGV -- there's a hint given in the description of the problem
Warning: large Input/Output data, be careful with certain languages
(though most should be OK if the algorithm is well designed)
Seems to work fine on my computer, except for the warning about using %ld (%lld should be used). I can only obtain a SIGSEGV error when putting 0 as a value for n[i]. Could you indicate what values you used to generate that error?
Edit :
You are testing for the values "1 888888888 1000000000".
Your computer simply can't allocate an array of such size. You are asking an array of size 1000000001 in your memory. That amounts to about 8GB (since a long long int as about 8B, at least on my computer), which is pretty much undoable for your computer.

Reading pixel data of a PPM file using C

I am trying to read pixel data from a PPM file. I have a function to read the header so I know it's pointing to the beginning of the pixel data. I tried using fgetc(file) but if the value is more than one digit it will not work. I also tried using an array and converting the array to an int or char but I have no way of knowing how many digits each value is. I'm also not sure if the values are separated by whitespace or not. Basically I need a way to extract the pixel data. (I'm using C.)
My code right now is:
char read_byte(FILE *ipt) {
int c, i=0, sum=0;
while (i<16) {
c=fgetc(ipt);
if((i%2)!=0 {
if(c&1) {
sum+=pow(2,i/2);
}
}
i++;
}
return (char)sum;
}
EDIT:
At first I thought the file was stored as the ASCII values, then I realized it's stored as binary. Right now I think I'm making it act like hex. I'm not sure if that's correct. I'm really stuck.
EDIT: changed my code a bit
char read_byte(FILE *ipt) {
int c, i=0, sum=0;
while(i<8) {
c = fgetc(ipt);
c=c&1;
sum+=c*pow(2,i);
i++;
}
return sum;
}
I print the sum as %c
Must you write this for an assignment, or is it for pleasure, or could you use someone else's code?
There is an Open Source solution.
"Netpbm is a package of graphics programs and a programming library. " which includes programs to read PPM at http://netpbm.sourceforge.net/doc/
Edit:
Have you got, or read the definition of the file format, e.g. http://netpbm.sourceforge.net/doc/ppm.html?
It looks like the data is either sequences of one byte RGB triples, or sequences of two byte RGB triples.
The program can detect which format is used from item 7 "The maximum color value (Maxval)". It says "If the Maxval is less than 256, it is 1 byte. Otherwise, it is 2 bytes."
So you code a function which reads one byte/component RGB data, then code another to read two byte/component RGB data.
The program can choose which to call once it has read the value of Maxval.
Edit {
According to the document at that link, the image data in a 'P6' ppm is binary.
So if MaxValue is <256, and hence the data for each colour component is one byte, then reading three bytes, with three calls of fgetc(fp) would return the binary value of one RGB pixel.
If the program has read the header, it has the values of width and height for the image data. So it could allocate an array for every row (width wide of RGB pixels), and an array of pointers to each allocated pixel row array. Then read the binary data into each row, and the program has something straightforward to operate on; a 2d array.
} end edit
My reading of your question suggests you already know how to read one byte data using fgetc.
Edit - it seems like this is irrelevant:
You can read two byte data by calling fgetc twice, and shifting and bit or-ing the data, e.g. (partly ignoring error checking):
int a = fgetc(fp);
int b = fgetc(fp);
if (a >= 0 && b >= 0) { // then all is okay
unsigned int twobyte = (a<<8) | b; // or (b<<8) | a; depending on byte order
// ...

Resources