Find a triad in a network with a C program - c

I've the following problem: I have two file file1.dat and file2.dat with 9 numbers put in a column each. For exemple:
file1.dat = 1,1,1,2,2,4,4,4,7
file2.dat = 2,4,7,3,4,1,3,7,1
I've tried to write a program that should find the triad in this network, where for triads I mean a group of three numbers that start with one of this number, pass to another two that are linked toghether and return back to the original one. In this case the file1.dat describe the "nodes" from where to start, and file2.dat describe the nodes where you arrive (1->2, 1->4, 1->7, 2->3 ...). There are two triads in this little "network" and they are composed from 1,2,4 and 1,4,7. I wrote the following program:
#include <stdio.h>
#include <stdlib.h>
#define N 9
int main (void){
int A[N],B[N],i,j,l,m,k;
int x,y;
int valueA,valueB,count,middle_value,new_value;
FILE *fp,*fq;
if ((fp = fopen("file1.dat", "r")) == NULL ) {
printf("Error opening file 1\n");
exit(EXIT_FAILURE);
}
for (i = 0; i < N; i++) {
fscanf(fp,"%d", &x);
A[i] = x;
}
if ((fq = fopen("file2.dat", "r")) == NULL ) {
printf("Error opening file 2\n");
exit(EXIT_FAILURE);
}
for (i = 0; i < N; i++) {
fscanf(fq,"%d", &y);
B[i] = y;
}
the up code is used to fill the two array A and B with all the data in the two files.
for (i=0;i<N;i++){
valueA=0;
valueB=0;
valueA=A[i];
valueB=B[i];
count=0;
middle_value=0;
new_value=0;
//Start the research of the first node of the file2.dat in the file1.dat
for(k=i+1;k<N;k++){
if(A[k]==valueB){
count++;
Up here I put a counter "count" that increase to 1 let me know if I find in the first file some number that have the same value as the first attending node. Now if the counter = 1, I want the computer to memorize the valueB = A[k] to write it at the end of the file as the middle term of the triad. Then I give to "valueB" the new value that is the "node arrival" corrisponding at the start one of A[k]--> B[k];
if(count==1){
middle_value = valueB;
valueB = B[k];
Then I look forward in the file, icreasing the for from where I stop before (l = k+1 ) for the last value of the triad that have to be like A[l] --> first value of A == B[l]. I increase then the counter and when the counter reach 2 the program should print me the 3 values, otherwise it should leave counter == 1, and if it can't find the first valueB in the file1, leave the counter == 0 (that's why I put the else at the end..)
for(l=k+1;l<N;l++){
new_value=A[l];
if(new_value==valueB && valueA==B[l]){
count++;
if(count==2){
printf ("%d,%d,%d\n\n",valueA,middle_value,valueB);
}else{
count=1;
}
}
}
}else{
count=0;
}
}
}
}
fclose(fp);
fclose(fq);
return (0);
}
But it doesn't work as I want. But if, e.g., I create 2 new files like
file1.dat = 1,1,1,2,3
file2.dat = 2,4,7,3,1
where there is the triad 1,2,3, the program works (must put # define N 6 in the 3rd row).. Someone can help me?
The problem that I think to have is that the program, with the beginning files, when it associate to valueA = 1, valueB=2, then it looks again to file 1 the position of 2 (that now becomes "the middle_value") and it gives to the new valueB = 3. Now it will search the 3 in the file1 but it don't find it. So it should pass at the second '2' that is in the file1 and give to the new valueB = 4 and then everything should goes well. But it doesn't. I don't understand why

So, I see a number of problems with your method. Perhaps the biggest problem is that you have three loops:
for(i=0 ;i<N;i++){
for(k=i+1;k<N;k++){
for(l=k+1;l<N;l++){
And each loop begins where the other ends. But, in general, you may need to look at smaller nodes in order to find loops. For instance, if you have the following graph:
1 2 3
3 1 2
you can verify that your approach will not work. So we know right away that we need to expand the range of the loops.
Also, you have a lot of variables floating around. Sometimes (but not always), that's an indication that the program is needlessly complex. Often times, considerably complicated problems can be solved without too many intermediate variables.
Your x and y variables were obviously unnecessary because you were using them as simple intermediates, so I cut them.
You used two file pointer variables, but really only needed one. I cut out the second one.
I also moved the fclose statements closer to where you read in the files, so that they would be open for the shortest possible time, which is a polite way to read a file.
Your valueA, valueB, and count variables immediately struck me as being questionable. Especially this bit:
valueA=0;
valueB=0;
valueA=A[i];
valueB=B[i];
You give them values, and then immediately change the values.
But a deeper look at the code shows that you're using valueA and valueB to keep track of which A and B you're looking at. And you use count to keep track of how deep you are in the loops. But each of these is inherent in the structure of the code!
So I cut all that out and widened the loop range, as discussed above, resulting in this:
#include <stdio.h>
#include <stdlib.h>
#define N 9
int main () {
int A[N], B[N];
FILE *fp;
if ((fp = fopen ("file1.dat", "r")) == NULL) {
printf ("Error opening file 1\n");
exit (EXIT_FAILURE);
}
for (i = 0; i < N; i++)
fscanf (fp, "%d", &A[i]);
fclose (fp);
if ((fp = fopen ("file2.dat", "r")) == NULL) {
printf ("Error opening file 2\n");
exit (EXIT_FAILURE);
}
for (i = 0; i < N; i++)
fscanf (fp, "%d", &B[i]);
fclose (fp);
for(int i=0; i<N; i++)
for(int j=0; j<N; j++)
for(int k=0; k<N; k++)
if(B[i]==A[j] && B[j]==A[k] && B[k]==A[i])
printf("%d,%d,%d\n",A[i],A[j],A[k]);
return 0;
}
It will find each triad-loop three times, which is unfortunate, but it will find all the loops. There are slightly more complicated algorithms which would find loops once or find them more efficiently, but this algorithm most closely matches your original code, so it may be the most useful for you now.

Related

A function that inserts array into a binary file

My task is to write a function unesi_niz which allows the user to enter array of real numbers (maximum 100) where the entry ends with entering the number -1. The array that is entered in this way should be written to the binary file niz.bin as values of type double. The file must not contain anything other than members of the string (so it must not contain the entered number -1).
Then write a srednja_vrijednost function that calculates the mean value of the numbers in the niz.bin file and returns it. If the file does not exist or is empty, 0 should be returned.
So i started like this:
#include <stdio.h>
#include <stdlib.h>
#define vel 100
int i = 0;
int j = 0;
void unesi_niz() {
double pomocna;
double niz[100];
while (i != 100) {
scanf("%lf", &pomocna);
if (pomocna != -1) {
niz[i] = pomocna;
i++;
} else
break;
}
FILE *ulaz = fopen("niz.bin", "w");
if (!ulaz) {
printf("Greska pri otvaranju.\n"); //opening fault
}
for (j = 0; j < i; j++) {
fwrite(niz, sizeof(double), j, ulaz);
}
fclose(ulaz);
}
double srednja_vrijednost() {
double suma = 0;
if (i == 0)
return 0;
FILE *ulaz = fopen("niz.bin", "r");
if (!ulaz) {
printf("Greska pri otvaranju.\n");//opening fault
return 0;
}
double niz[100];
fread(niz, sizeof(double), i, ulaz);
int j;
for (j = 0; j < i; j++) {
suma += niz[j];
}
fclose(ulaz);
return suma / i;
}
int main() {
unesi_niz();
double n=srednja_vrijednost();
printf("%g\n", n);
return 0;
}
My code has several problems. the first is the wrong return value of the function srednja_vrijednost, when I enter the values 5 10 15, the result is 1.6667, which is nonsense, and then many "Profiler errors", my debug console says Error in line 56, main.c file: The program accesses a variable that is not initialized, however I don't see any "Forbidden Action".
Hope some of you can see what I have done wrong :)
Your code fails in unesi_niz at these lines:
for (j = 0; j < i; j++) {
fwrite(niz, sizeof(double), j, ulaz);
}
fwrite takes a pointer to the data, the size of individual elements in bytes and the number of such elements. This means your code writes j elements starting from the first element each time. You probably want to write 1 element each time. Or better yet, you want to write all i elements, since fwrite allows you to write more than one element.
fwrite(nix, sizeof(double), i, ulaz);
As an aside, your "srednja_vrijednost" logic will work, but only because you already know the size of your array in the current process (stored in i). I am not entirely sure what you are trying to do but I suspect you want to be able to read the same file back even after your process exits. For that, you would need some logic to find the size of the array. You can do this either by writing the length as well into the file, or (similar to the input) write an ending -1, or just figure out the size by calculating the file size.

How to increase the array block i want to manipulate

so my assignment is as follows:
"Write a program that reads in a list of numbers from an input text file called input.txt. For each number read, your program should determine and print out whether or not that number is abundant."
input.txt =
i have the code down and i think i finally figured out how to find and sum all the divisors to check if a number is abundant or not but the question i have is how do i go to the next array block to check the next number? Now it is checking "15" which is the first number to check(the 5 tells the program how many numbers it needs to check) but how do i get it to check the next number 3 and so on?
thank you!
#include <stdio.h>
#define SIZE 100
int main(){
FILE *ifp;
int cases;
int i;
int j;
int counter = 1;
int dividen =1;
int listArray[SIZE];
int sum = 0;
ifp = fopen("input.txt", "r");
fscanf(ifp,"%d", &cases);
for(i=0;i<cases;i++){
fscanf(ifp,"%d",&listArray[i]);
printf("%d\n", listArray[i]);}
while(listArray[0] > counter){
if(listArray[0] % dividen == 0){
sum = sum+dividen;
dividen++;
counter++;}
else{
dividen++;
counter++;}
}
if(listArray[0] > sum)
printf("\n%d is not an abundant number\n",listArray[0]);
system("pause");
return 0;
}
Move the code that checks abundance into the same loop where you store into listArray, or write another loop right after it that works on each element of listArray.
A good solution to problems like this in general is something like:
static const int TO_READ = 3; // For example.
FILE* file = open_input_file();
variable foo, bar, baz;
while ( TO_READ == fscanf( file, format, &foo, &bar, &baz )) {
do_stuff_with( foo, bar, baz );
}

Bubble sorting not working for large file, but it works for small file

I having issue with bubble sorting large data. This is an assignment, and my teacher explicitly said to use bubble sort to sort this large data. I tried running in a small file and it works perfectly, but it's having trouble outputting anything for big file. I don't know what's the problem. I have to use bubble sort too. Thank you. The small file "small.txt"is provided below. The big file "big.txt" does fit in here, it contains thousands of lines but the same format as the small file, and my program is provided below: I waited for 1 hour for anything to output, and the program is still in progress for the big file.
small.txt
FORD 2001
NISSAN 2000
JAYCO 2003
Program
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
FILE *read;
char lines[110000];
int i=0, c, j,a;
char *make[111100];
char *year[111100], *swapyear, *swapmake;
if( (read = fopen("big.txt", "r")) == NULL)
{
printf("can't open %s\n", "big.txt");
exit(1);
}
c=0;
while(fgets(lines, sizeof(lines), read)!=NULL){
make[c] = strdup(strtok(lines, " "));
year[c] = strdup(strtok(NULL, " "));
c++;
}
for(j=0; j<c-1; j++){
for(a=0; a<(c-j-1); a++){
if(atoi(year[a]) > atoi(year[a+1])){
swapyear = year[a];
swapmake = make[a];
year[a] =year[a+1];
make[a] = make[a+1];
year[a+1] = swapyear;
make[a+1] = swapmake;
}
}
}
for(j=0; j<=(c-1); j++)
{
printf("%s %s\n", make[j], year[j]);
}
}
This is the bubble sort algorithm.
Note that it extends all the way through the data on each pass
(unlike the OPs code)
Step 1: Repeat Steps 2 and 3 for i=1 to number of entries to sort
Step 2: Set j=1
Step 3: Repeat while j<=n
(A) if a[i] < a[j]
Then interchange a[i] and a[j]
[End of if]
(B) Set j = j+1
[End of Inner Loop]
[End of Step 1 Outer Loop]
Step 4: Exit
and here is a code implementation:
for(i=0 ; i<n ; i++)
{
for(j=0 ; j<n-i-1 ; j++)
{
if(arr[j]>arr[j+1]) //Swapping Condition is Checked
{
temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
The above uses a temp variable, usually a bad idea.
Here is an example of using the XOR operator (and no temp variable)
x = x ^ y (1)
y = y ^ x (2)
x = x ^ y (3)

Reading in a file to create multiple "minesweeper"ish arrays

What I got so far, is a .in file that will create 100 arrays, followed by how many "mines" are on the board, and then 2 numbers for each "mine" representing where they will be placed on the array. This is for my beginner C class, and honestly we've not been taught properly for something this advanced (i say advanced using the term lightly). I know how to read in files, and I know how to create an array, but im unsure how I would read in that many lines, switching from mines to placement over and over again. I also find myself confused as to how to change an array number from 0 to another number based on where a mine is placed.
An example input file:
1
4
1 3
7 5
7 3
3 3
Where the 1 in the first line means we have one board. The 4 on the next line means it will have 4 bombs. The following 4 lines describe the position of the bomb in the array as row column.
Is there anything that anyone can offer me to point me in the right direction?
Below is a partial solution, it leaves a few parts as an exercise for the OP.
#include <stdio.h>
#include <stdlib.h>
#define BOARD_SIZE 8
int main(void) {
FILE *fp;
fp = fopen("mines.in","r");
if ( fp == NULL ) {
fprintf(stderr,"Could not open file\n");
return 1;
}
int nBoards = 0;
int nMines = 0;
int col;
int row;
int currentBoard = 0;
/* We know the first row is going to be the number of boards */
fscanf(fp,"%d",&nBoards);
printf("We have %d boards\n",nBoards);
while ( fscanf(fp,"%d",&nMines) > 0 ) {
int i,j;
/* initialize board as all zeros */
int board[BOARD_SIZE][BOARD_SIZE] = { {0} };
currentBoard++;
printf("Board %d:\n",currentBoard);
/* Read in and set the mines */
for (i=0; i<nMines; i++) {
fscanf(fp,"%d %d",&col,&row);
board[col-1][row-1] = 9;
}
/* Add mine proximity */
for (i=0; i<BOARD_SIZE; i++) {
for (j=0; j<BOARD_SIZE; j++) {
if ( board[i][j] == 9 ) { /* we have a mine */
/* Square to the left */
if (j > 0 && board[i][j-1] != 9) {
board[i][j-1]++;
}
/* Square to the right */
/* Left as exercise for the OP*/
/* Square above */
/* Left as exercise for the OP*/
/* Square below */
/* Left as exercise for the OP*/
}
}
/* Print out the board */
for (i=0; i<BOARD_SIZE; i++) {
for (j=0; j<BOARD_SIZE; j++) {
printf("%d ",board[i][j]);
}
printf("\n");
}
printf("\n");
}
fclose(fp);
if (currentBoard != nBoards) {
fprintf(stderr,"Expected %d boards, read in %d boards\n",nBoards,currentBoard);
return 1;
}
return 0;
}
The code reads in the first line to record the number of boards, then it loops over the blocks of data containing the number of mines and the mine locations. The while loop will perform an fscanf on the lines containing the number of mines, and in the body of the while loop the different mine locations will be read in to the number defined for the board.
Once we have all the mine locations we can calculate the numbers in other squares on the board, only one of which I've shown in the code (others are similar).
Note that the above code does almost no error handling and almost no validation on the input file - if the input file is wrong you could get errors i.e. 'out of range' accesses to arrays. I've left out such checks to make the underlying logic of the program clearer.
Note also that I've assumed that the input indexs are '1'-indexed (i.e. in the range [1,8] rather than '0'-indexed as C expects (i.e. in the range [0,7]), hence the substitution of 1 in the line board[col-1][row-1] = 9;.

program in C is crashing when more memory is used

I have to do as a school assigment small program in C that will read standart input and prints some standart output. To be more specific, it's about reading numbers and sorting them.
(you can skip this, it's just for understanding the code)
First line of the input should determine how many lines of numbers there will be. Second line is ammount of numbers in next line. Third line are to concrete numbers. Fourth line is ammount of numbers in next line and so on until it reaches K number of lines. Restrictions are 0 < K <= 10 (max 10 sequences), each sequence can contain max 10.000.000 numbers and each number's value is max 10.000.000
Example
Input:
2 //which means that there will be 2 sequences (lines) of numbers and their corresponding ammount
3 //in the first sequence there will be 3 numbers
5 99912 45 //first sequence
6 //in the second sequence there will be 6 numbers
9489498 22131 0 521313 7988956 5 //second sequence
Ouptup:
0 5 5 45 22131 99912 521313 7988956 9489498
So I have done a working program but it seems to be unstable with higher values. However I can't determine when and where exactly the program fails. On my computer, I have tested all possible max values and it returned correct output in reasonable time, but on a school server where tests are done it just can't handle high values and fails.
There is one thing, that the program should only use C, not C++, but I am not very sure of differences between them and as I was using C++ compiler, it's possible that my code isn't just raw C.
I am a C beginner and this is something like "Hello world" for me, so please, can you just quick look through the code and say what can cause the unstability? Thanks
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int k, n, i, y, x, index = 0;
int *numbers = (int*) malloc(100000000 * sizeof(int));
if(numbers == NULL){
exit(1);
}
scanf("%d", &k);
for (x = 0; x < k; x++) {
y = 0;
scanf("%d", &n);
while(scanf("%d", &i) > 0){
numbers[index++] = i;
if(++y == n){
break;
}
}
}
for(y = 0;y < index;y++){ //find and print all 0's, because later I will use 0 as a
//already used (printed) element in array and ignore it
if(numbers[y] == 0){
if(y == index-1){
printf("0");
}else{
printf("0 ");
}
}
}
int smallest, smallestIndex;
for(x = 0;x < index;x++){ //print all other numbers in ascending order
smallest = 0;
for(y = 0;y < index;y++){ //find current smallest number
if((numbers[y] < smallest || smallest == 0) && numbers[y] != 0){
smallest = numbers[y];
smallestIndex = y;
}
}
numbers[smallestIndex] = 0;
if(smallest > 0){
if(x == index-1){
printf("%d", smallest);
}else{
printf("%d ", smallest);
}
}
}
free(numbers);
numbers = NULL;
return 0;
}
Based on the information you give, I think this is simply a resource limitation on the server. The server simply runs out of memory and your malloc() fails. I suggest you debug or do this:
if(numbers == NULL){
printf("malloc() failed\n");
exit(1);
}
The code for printing the initial zeros is suspicious:
for(y = 0;y < index;y++){ //find and print all 0's, because later I will use 0 as a
//already used (printed) element in array and ignore it
if(numbers[y] == 0){
if(y == index-1){
printf("0");
}else{
printf("0 ");
}
}
Suppose you have a sequence with 0 as the last element (e.g. 1 2 3 4 5 0); i guess this code will print just 0 with no space after it, and the subsequent code will print 1 2 3 4 5, so you will get something like 01 2 3 4 5.
I understand that you want the output to be as beautiful as possible, that is, without a space at the end. Please also note that a newline (\n) at the end of output might be good.
I rewrote beginning parts of your program to get you on the right path. This should help you but I can't be sure since I don't really know what is causing your program to crash.
This implements the realloc function which should make your program drastically more efficient than it is now. If you don't know what realloc is you can read about it here, and here.
#include <stdio.h>
#include <stdlib.h>
#define BUFFER 256 //for memory management
int main(void)
{
int k, n, i, y , x, index = 0, bff; //declare integer 'bff' and set it to BUFFER
int *numbers = NULL, *tmp; //declare a pointer (numbers) for allocated memory, and a pointer (tmp) for the realloc function
if(!(numbers = malloc(BUFFER * sizeof(int)))) //allocate space for 'bff' integers
{
exit(1); //allocation failed
}
scanf("%d", &k);
for (x = 0; x < k; x++)
{
scanf("%d", &n);
while(scanf("%d", &i) > 0)
{
if(bff <= index) //if the size of index grows larger than the amount of space we allocated
{
bff += BUFFER; //increase the size of bff by BUFFER
if(!(tmp = realloc(numbers, bff * sizeof(int)))) //resize our allocated memory block using the tmp pointer
{
free(numbers); //allocation failed so free already allocated memory
exit(1); //and terminate the program
}
numbers = tmp; //make numbers point to the same location as tmp
numbers[index++] = i;
if(++y == n) break;
}
}
}
.
.
.
free(numbers);
return 0;
}
Keep in mind there are more efficient ways to use realloc. I just posted this here to get you on the right track. Good luck!
You are allocating the wrong amount of memory. The specification states that each sequence can contain 10 million values whereas you allocate a fixed amount. There may be up to k*10 million values of input, and you cannot know that the amount you allocate is enough.
As pointed out by m0skit0, the problem may also be due to over-allocation.
To fix the problem you should allocate the needed amount of memory, no more, no less.
Use the sequence length provided for each sequence to do that.
Also, you need to check the return value of malloc and realloc. If the return value is NULL then the allocation failed and you should print an error message and exit.

Resources