I'm trying to read a file and store what it contains, but I'm getting segmentation fault, here is part of my code:
int nnodes;
int main(){
FILE * file = fopen("pub08.in", "r");
int nkeys;
fscanf(file, "%d %d", &nnodes, &nkeys);
long int graphsize = nnodes * nnodes;
long int * graph = malloc(graphsize * sizeof (long int));
for (int i = 0; i < graphsize; i++) {
graph[i] = IN;
}
for (int i = 0; i < nnodes; i++) {
long int a, b, prize;
fscanf(file, "%ld %ld %ld", &a, &b, &prize);
graph[a * nnodes + b] = prize;
graph[b * nnodes + a] = prize;
}
}
the file pub08.in looks like this:
100000 10000
61268 56095 10
40567 20917 17
97937 47973 13
74088 21826 13
62183 30464 11
97793 80708 12
35121 90180 10
77067 97297 17
4657 33995 16
88147 42709 18
95937 25936 19
79853 24452 11
9677 36288 11
91869 48767 15
34585 46478 17
41874 40622 15
13700 19942 18
15660 79277 14
...
Full file is here
The segmentation fault happens, I think, on line:
graph[a * nnodes + b] = prize;
What am I doing wrong?
Here is a list of things you are doing wrong:
Check the return values from fscanf.
Validate a and b to ensure that they are in range.
Check the return value from malloc
As per comment - check the return value from fopen
Related
so what I have is the following array:
10
1 250 350 50
2 525 200 80
3 425 700 60
4 675 475 65
5 850 850 40
6 925 200 90
7 1050 575 80
8 1250 800 70
9 1375 400 60
10 1500 650 40
Each lines' value means something different, per instance
1 250 350 50
id lat long value
I want to assign each of those line values to a structure so I can play with them, but after googling and coming up with the graph theory (which is kind of similar to what I am trying to do) nothing worked... I may say that this array is being pulled from a text file, whether that is or not relevant.
struct population{
int id;
int latitude;
int longitude;
int value;
};
I can't come up with any solution, can anyone help me out or at least provide some tutorials or articles to help me clear my mind?
Here is my code:
#include <stdio.h>
#include <math.h>
#include <string.h>
#define RSIZE 20
#define CSIZE 11
struct population{
int id;
int latitude;
int longitude;
int value;
};
int main(void)
{
char line[CSIZE][RSIZE];
char fname[20];
FILE *fptr = NULL;
int i = 0;
int tot = 0;
printf("\n\n Read the file and store the lines into an array :\n");
printf("------------------------------------------------------\n");
printf(" Input the filename to be opened : ");
scanf("%s",fname);
fptr = fopen("cord.txt", "r");
while(fgets(line[i], RSIZE, fptr))
{
line[i][strlen(line[i]) - 1] = '\0';
i++;
}
tot = i;
printf("\n The contents of the file %s are : \n",fname);
for(i = 0; i < tot; ++i)
{
printf(" %s\n", line[i]);
}
printf("\n");
return 0;
}
A good way to read, validate and save a line of file text into a struct is to use a helper function with fgets() and sscanf() #kaylum. Use " %n" to detect successful parsing completion.
#define INT_TEXT_SIZE 12 // INT_MIN
#define POPULAITON_LINE_SIZE ((INT_TEXT_SIZE + 1 /* separator */)*4 + 1)
// Return:
// 1 on success
// 0 on failure
// EOF on end-of-file/input error
int population_read(struct population *p, fptr) {
// Be generous in buffer size, suggest 2x max expected
char buf[POPULAITON_LINE_SIZE * 2];
if (fgets(buf, sizeof buf, fptr) == NULL) {
return EOF;
}
int n = 0;
// Use %n to store offset
sscanf(buf, "%d%d%d%d %n", &p->id,
&p->latitude, &p->longitude, &p->value, &n);
if (n == 0 || buf[n] || n >= sizeof buf - 1) {
// Parsing failed, junk at the end or very long
return 0;
}
// Maybe some range/value tests per member
if (p->latitude < LATITUDE_MIN || p->latitude > LATITUDE_MAX) {
return 0;
}
... // likewise for other members.
return 1;
}
Usage example:
struct population pop[CSIZE];
int count;
for (count = 0; count < CSIZE; count++) {
int result = population_read(&pop[count], fptr));
if (result == 0) {
report_error_with_TBD_code();
return -1;
}
if (result != 1) {
break;
}
}
for (int c = 0; c < count; c++) {
// Use pop[c];
}
Random numbers are printed in "numbers.txt". "numbers.txt" exists as a single line. The values here will be taken as two digits and assigned to the queue. I'm having trouble with the while part.
When the numbers in the Numbers.txt file are separated by two digits, I want to make the 0 in the tens digit a 1.
Example
numbers.txt :
839186660286459132876040232609
Output:
two-digit
83 91 86 66 2 86 45 91 32 87 60 40 23 26 9.
As you can see 02 and 09 written as 2 and 9. i want to 12 and 19.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define SIZE 30
typedef struct stack
{
int value;
} Stack;
int *first, *last, *queue;
void kuyrukList()
{
printf("\nKuyruktaki Elemeanlar\n");
int *temp = first;
while (temp < last)
{
printf("%d ", *temp);
temp++;
}
}
void insert(int value)
{
*last = value;
last++;
}
int main()
{
//Random number.
srand(time(NULL));
int text[30] = {0};
FILE *dosyaYaz = fopen("numbers.txt", "w");
printf("\nOlusturulan number degeri:\n");
for (int i = 0; i < SIZE; i++)
{
text[i] = (rand() % 10);
printf("%d", text[i]);
fprintf(dosyaYaz, "%d", text[i]);
}
fclose(dosyaYaz);
printf("\n ");
//***********************************
char ch;
int number = 0;
int counter = 1;
queue = (int *)malloc(sizeof(int) * SIZE);
first = queue;
last = queue;
FILE *dosyaAc = fopen("numbers.txt", "r");
if (dosyaAc == NULL)
{
printf("\nDosya bulunamadi.\n");
exit(0);
}
while ((ch = fgetc(dosyaAc)) != -1)
{
if (counter % 2 == 1)
{
number += (ch - '0') * 10;
}
if (counter % 2 == 0)
{
number += (ch - '0');
insert(number);
number = 0;
}
counter++;
}
fclose(dosyaAc);
kuyrukList();
return 0;
}
So you are creating random numbers, but afterwards you modify them when they are smaller than 10? The easiest solution is to create random numbers who only vary from 10 to 99. This can be done as follows:
Imagine that double rand() generates a random number from 0 to 1 (both never being generated).
Then, 90 * rand() generates a random number from 0 to 90 (both never being generated).
Then, 10 + 90 * rand() generates a random number from 10 to 100 (both never being generated).
Then, (int)(10 + 90 * rand()) generates a random natural number, from 10 to 99 (both might be generated because of the rounding mechanism).
It appears from your stated goals that an array of 15 numbers ranging from 10 - 99 is the need. If that is true, skip writing to a file, and reading them back as a intermediate step and just create an array of 15, two digit numbers directly.
To do this, consider using a function to accept range and offset parameters (upper and lower values) and an array sized for each of the values to use with configuring rand(),.
The following can serve as the core of what you are doing by generating an array of pseudo randoms in the range you specify:
//generate an array of pseudo random values between lower and upper values
void gen_rand(int lower, int upper, int count, int *arr)
{
int i;
for (i = 0; i < count; i++)
{
arr[i] = (rand() % (upper - lower + 1)) + lower;
}
}
int main(void)
{
int arr[15];
srand(time(NULL));
gen_rand(10, 99, 15, arr);
return 0;
}
I have a text file with a large matrix (56*10000). But here is a sample.
A B C D
1 3 4 5
3 5 6 10
2 2 6 11
3 2 3 38
3 3 1 19
I have a code which can read the file and also print it. I have two problems.
I can't seem to find a way to print a particular column. For example in MATLAB, if we want to print the second column we indicate it like [:,2].
Is there way where I can access the column by a particular name. For example, since these columns are named A B C D, if I want to print the second column, I just have to say, if case in B, print (B) and it has to print,
3
5
2
2
3
Here is the code that I have.
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE * fp;
int M = 5, N = 4;
char filter[1024] ;
double *Z_BS = (double *)malloc(M * N * sizeof(double));
fp = fopen("test.txt","r");
if (fp == NULL)
{
exit(1);
}
fgets(filter,1024,fp);
for (int rows = 0; rows < M; rows++)
{
for (int cols = 0; cols < N; cols++)
{
fscanf(fp, "%lf", Z_BS);
printf("%lf\t", *Z_BS);
}
printf("\n");
if (feof(fp))
{
break;
}
}
}
In C there is no way like matlab, but with the help of below idea you can generate the required offset
offset = row_size*i + column_number
lets say there are five 5 rows and 5 columns and you want to access 3 column.
A B C D E
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25
when i = 0, 5*0+3 = 3
when i = 1, 5*1+3 = 8
when i = 2, 5*2+3 = 13
when i = 3, 5*3+3 = 18
when i = 4, 5*4+3 = 23
NOTE: check for EOF always or the offset is valid before using, you should not access anything beyond the file.
Unrelated, but if you just want to print the values, there's no need to allocate memory.
Using a local variable is enough
for (int rows = 0; rows < M; rows++) {
for (int cols = 0; cols < N; cols++) {
double Z_BS;
fscanf(fp, "%lf", &Z_BS);
printf("%lf\t", Z_BS);
}
printf("\n");
if (feof(fp)) {
break;
}
}
To print just one column, you can simply use the col variable, say print the second column
for (int cols = 0; cols < N; cols++) {
double Z_BS;
fscanf(fp, "%lf", &Z_BS);
if (cols == 1)
printf("%lf\t", Z_BS);
}
It says cols == 1, because the loop starts at 0 (first column = 0, second column = 1, ...).
To print by column name, don't skip the first row, but compare the name, e.g.
char colname[] = "B";
int colnum;
// Scan header row
for (int cols = 0; cols < N; cols++) {
char current[51];
fscanf(fp, "%.50s", current);
if (strcmp(current, colname) == 0) {
colnum = cols;
break;
}
}
and later while printing
if (cols == colnum)
printf("%lf\t", Z_BS);
I have some code and some test cases. First case passed, second failed.
I don't understand what the problem is.
Problem:
You are given N triangles, specifically, their sides a[i], b[i] and c[i]. Print them in the same style but sorted by their areas from the smallest one to the largest one. It is guaranteed that all the areas are different.
I'm using Heron's formula:
double p = (a + b + c) / 2;
double area = sqrt(p*(p-a)*(p-b)*(p-c))
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
struct triangle
{
int a;
int b;
int c;
};
typedef struct triangle triangle;
double area(int a, int b, int c)
{
a = (double) a;
b = (double) b;
c = (double) c;
double p = (a + b + c) / 2;
return sqrt(p*(p-a)*(p-b)*(p-c));
}
int compareTringle(const void* left, const void* right){
double leftArea = area(((triangle *)left)->a, ((triangle *)left)->b,
((triangle *)left)->c);
double rightArea =
area(((triangle *)right)->a, ((triangle *)right)->b,
((triangle *)right)->c);
if (leftArea > rightArea)
return 1;
if (leftArea < rightArea)
return -1;
return 0;
}
void sort_by_area(triangle* tr, int n) {
qsort(tr, n, sizeof(triangle), compareTringle);
}
int main()
{
int n;
scanf("%d", &n);
triangle *tr = malloc(n * sizeof(triangle));
for (int i = 0; i < n; i++) {
scanf("%d%d%d", &tr[i].a, &tr[i].b, &tr[i].c);
}
sort_by_area(tr, n);
for (int i = 0; i < n; i++) {
printf("%d %d %d\n", tr[i].a, tr[i].b, tr[i].c);
}
return 0;
}
First test:
Input:
3
7 24 25
5 12 13
3 4 5
Output:
3 4 5
5 12 13
7 24 25
It passed
Second case: https://pastebin.com/DFBGz2KD
What's wrong?
This isn't doing what you want:
a = (double) a;
b = (double) b;
c = (double) c;
The problem is that the variables a, b, and c are still integers. So you're converting them to double, then they're being implicitly converted back to integers and stored back as integers. Then the following doesn't work:
double p = (a + b + c) / 2;
since a + b + c is an integer, so the division is integer division.
You could fix it by doing:
double da = a;
double db = b;
double dc = c;
and then using da, db, dc in place of a, b, c.
But if you'd rather let the compiler perform the type promotions for you, you can get rid of the assignments and instead just change the assignment to p to:
double p = (a + b + c) / 2.0;
This will add a, b, and c as integers, then convert the result to double since it's now dividing by a double constant, 2.0.
Either way will work.
Tom has given you a good answer to solve your integer promotion problem, but there are a number of of issues just inviting Undefined Behavior and a number of other nits you can clean up.
First, you must always validate ALL input. Otherwise, you have no clue whether a matching or input failure occurred with scanf and you are blindly making use of values that will be indeterminate in the case of either failure. Simply validate the return of scanf, e.g.
if (scanf("%d", &n) != 1) { /* validate every input */
fputs ("error: invalid formate - 'n'.\n", stderr);
return 1;
}
...
for (int i = 0; i < n; i++)
if (scanf("%d%d%d", &tr[i].a, &tr[i].b, &tr[i].c) != 3) {
fputs ("error: invalid format - a,b,c.\n", stderr);
return 1;
}
You must validate every allocation (whether using malloc, calloc or realloc) for the exact same reason. It is not a matter of "if" and allocation will fail, it is a matter of "when". Since an allocation failure sets errno, your error reporting is a trivial call to perror, e.g.
triangle *tr;
...
if (!(tr = malloc (n * sizeof *tr))) { /* validate every allocation */
perror ("malloc-tr");
return 1;
}
Nits. In C when you declare a function and leave the parenthesis empty () you have specified that the function takes an unspecified number of arguments, not zero. To make you declaration of main() conforming, you should use:
int main (void) {
See: C11 Standard - ยง5.1.2.2.1 Program startup(p1)
There is no need for any of your casts in area, simply resolve the integer division problem by adding a '.' after the 2 and let default promotions handle the rest, e.g.
double area (int a, int b, int c) /* remove all casts, add '.' after 2 */
{
double p = (a + b + c) / 2.;
return sqrt (p*(p-a)*(p-b)*(p-c));
}
While you are free to declare the struct and typedef separately, you can do it in a single declaration as well, e.g.
typedef struct { /* you can simply create the typedef */
int a, b, c;
} triangle;
After you fix your integer division issue, your code will work fine, but you should fix the other issues to make sure you don't run off into Undefined Behavior due to a foreseeable input of allocation error. With the integer division fixed, running against your test input will result in:
Example Use/Output
$ ./bin/triangle_sort_area < dat/triangles_20.txt
22 18 5
31 41 14
20 23 21
54 62 11
26 41 65
58 31 31
20 39 32
26 41 62
44 48 18
23 37 47
53 18 54
28 36 40
31 46 39
33 45 49
57 33 45
28 56 56
41 38 55
55 44 44
48 49 67
58 61 50
here is the problem count and say
my accept code below here. I wrote the main function,when submit just copy the countAndSay function.
#include <stdio.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
char* countAndSay(int n)
{
if( n == 1 )
return "1";
char *cur = (char *)malloc(2*sizeof(char));
char *res;
cur[0]='1';
cur[1]='\0';
int len, idx, j, count;
for(int i = 2; i <= n; ++i)
{
len = strlen(cur);
res = (char *)malloc(len * 2 + 1);
memset(res, '\0', len * 2 + 1);
count = 1;
for(idx = 1, j = 0; idx < len; ++idx)
{
if(cur[idx] == cur[idx-1])
{
++count;
}
else
{
res[j++] = '0' + count;
res[j++] = cur[idx-1];
count = 1;
}
}//end of for
res[j++] = '0' + count;
res[j++] = cur[len-1];
free(cur);
cur = res;
}
return cur;
}
int main()
{
char *s = countAndSay(INT_MAX);
printf("%s\n",s);
free(s);
return 0;
}
This code i saw from the discuss part and modfiy part of it.I just confused
why use res[j++] = '0' + count since count may be 11 or 12,when count bigger than 9,res[j++] is not a char between '0' and '9',so i ran the code,and it went wrong.
ctci(1720,0x100392380) malloc: * mach_vm_map(size=18446744071713468416) failed (error code=3)
* error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
Program ended with exit code: 9
i guess may be the series is too long,my computer's memory not enough.So i change the num to 500,still got wrong.
Just can not figuer out why.
following the advice of #WhozCraig,i print the len to malloc,here is the result.
1
2
2
4
6
6
8
10
14
20
26
34
46
62
78
102
134
176
226
302
408
528
678
904
1182
1540
2012
2606
3410
4462
5808
7586
9898
12884
16774
21890
28528
37158
48410
63138
82350
107312
139984
182376
237746
310036
403966
526646
686646
894810
1166642
1520986
1982710
2584304
3369156
4391702
5724486
7462860
9727930
12680852
16530884
21549544
28091184
36619162
47736936
62226614
81117366
105745224
137842560
179691598
234241786
305351794
398049970
518891358
676414798
881752750
1149440192
ctci(1828,0x100392380) malloc: *** mach_vm_map(size=18446744071713468416) failed (error code=3)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
Program ended with exit code: 9
so 1149440192B ,1149440192/(1024*1024)MB=1096MB,i just watch the memory left,it is bigger than 1096.1915893555MB.
You ran out of memory.
Every pass around the loop for(int i = 2; i <= n; ++i) potentially doubles the size of res, and you called it with n == INT_MAX. Ain't no computer in the universe that can allocate 1<<INT_MAX bytes of RAM.
The problem statement says to run for n == 30. Your output suggests enough RAM to run for 30.