Segmentation Fault 11 using nested loops with arrays - arrays

I'm not sure why I'm receiving this error. I was wondering could it be due to my terminal not being able to read the txt files that run with this program. Let me know if that could be a possible reason for that message.
Im mainly just looking for syntax errors. The files I have just contain a big bunch of numbers and I'm supposed to work from the third value onwards {the first two have another use)
#include <stdlib.h>
#define N 1000000
int main(void)
{
int n; /* The number of lengths */
int x; /* The target length */
int lengths[N]; /* The array of available lengths */
int i, j;
int whichfile=1;
FILE *fp;
scanf("%d", &whichfile);
switch (whichfile) {
case 1:
fp = fopen("testcase_small_sorted.txt", "r");
break;
case 2:
fp = fopen("testcase_large_sorted.txt", "r");
break;
case 3:
fp = fopen("testcase_small_nomatch_sorted.txt","r");
break;
case 4:
fp = fopen("hidden_small_sorted.txt","r");
break;
case 5:
fp = fopen("hidden_large_sorted.txt","r");
break;
}
fscanf(fp, "%d", &x);
fscanf(fp, "%d", &n);
for (i=0;i<n;i++)
fscanf(fp, "%d", &lengths[i]);
fclose(fp);
/* Now all the input data has been read in
search for the required pair of lengths... */
x = lengths[0];
n = lengths[1];
for(i = 2; i < n; i++)
{
for(j = 2; i < n; j++)
{
if(lengths[i] + lengths[j] == x)
{
printf("Found: %d + %d == %d\n", lengths[i], lengths[j], x);
}
}
}
return 0;
} ```

I'm mainly just looking for syntax errors.
Syntax errors are only the beginning. C will not check anything for you. You have to check if files opened, if input scans worked, if values are inside array bounds. If you don't, that's how you get segfaults.
For files, the usual pattern is to try to open the file, check its return value, and then handle the error. fopen returns NULL on error and sets errno. errno is a global which holds what sort of error happened like "file not found", but it's a number. strerror is handy to turn it into an error message. Finally fprintf is like printf but can print to things other than stdout. In this case stderr. Both stdout and stderr normally appear on the screen, but they can be separated.
FILE *fp = fopen(path, mode);
if( fp == NULL ) {
// This will print something like "Could not open testcase_small_sorted.txt: No such file or directory"
fprintf(stderr, "Could not open file %s: %s", path, strerror(errno));
exit(1);
}
But now we need to copy this five times because the code repeats fopen. Instead of each case opening the file, what if it just picked a filename? And since each filename has a number, what if they were just in an array?
const char *files[] = {
NULL, // 0 is not used
"testcase_small_sorted.txt",
"testcase_large_sorted.txt",
"testcase_small_nomatch_sorted.txt",
"hidden_small_sorted.txt",
"hidden_large_sorted.txt"
};
const char *path = files[whichfile];
What if they input something that's not a number? Or what if the number is out of range? These need to be checked for as well. scanf will return the number of items matched. We expect 1. If we get anything else it didn't work.
// Check that we read an integer.
if( scanf("%d", &whichfile) != 1 ) {
fprintf(stderr, "Please enter 1-5.\n");
exit(1);
}
// Check that it's in range.
if( (whichfile < 1) || (5 < whichfile) ) {
fprintf(stderr, "Please enter 1-5.\n");
exit(1);
}
Note that scanf has a lot of problems and should be swiftly discarded once you learn things like fgets and sscanf.
int lengths[1000000] is 4 to 8 megabytes (1 million integers at 4 or likely 8 bytes per integer) and might get you an eponymous stack overflow. Your algorithm is O(n^2) which means if there really were 1,000,000 items it would take 1,000,000,000,000 iterations to find all the pairings and your class will probably be done before the program is.
(A little hint to improve the algorithm: if the numbers are sorted, and you're looking for two of them to sum X, do you need to check every number?)
I think you're meant trust n from the file for how many to read. Normally you don't have this, it's a crutch to let you read input without using dynamic memory (you'll be taught that later). Even if you had it, you wouldn't trust it anyway in production code; if it lies you'll walk out of your array bounds. But for this exercise that's fine.
// Read the first two lines, the sum and the number of remaining lines.
// Note that `fscanf` can also fail and needs to be error checked.
// I'll leave that as an exercise.
fscanf(fp, "%d", &x);
fscanf(fp, "%d", &n);
// Use `n` to allocate just enough space on the stack.
int lengths[n];
// Read the rest.
// Use braces, even for one line.
// They avoid a very silly and hard to debug mistake.
for (i=0;i<n;i++) {
fscanf(fp, "%d", &lengths[i]);
}
fclose(fp);
There's no need to put x and n into lengths. They aren't meant to be summed and you skip over them anyway by starting your loops at 2.
With that fixed the loops can start at 0. There is a mistake in the inner loop, it should check j < n not i < n.
for(i = 0; i < n; i++)
{
for(j = 0; j < n; j++) // <<--- j < n, not i < n.
{
if(lengths[i] + lengths[j] == x)
{
printf("Found: %d + %d == %d\n", lengths[i], lengths[j], x);
}
}
}

Related

C: Reading multiple values with scanf and saving them into an array

I found an answer to the first part of my question (how to read multiple values with scanf) but it doesn't seem to work for me (I think it's because of putting the values into an array and maybe also because I'm checking if the values given are 6 ints for sure):
I am writing a program that stores co-ordinates of 4 triangles in an array. Each line has 6 values and stores co-ordinates of one triangle. I want to read 6 co-ordinates at one time and do this operation for 4 triangles separately.
int tab[4][6];
for (int i = 0; i < 4; i++){
while (scanf("%d %d %d %d %d %d", &tab[i][0], &tab[i][1], &tab[i][2], &tab[i][3], &tab[i][4], &tab[i][5]) != 6){
printf("Error, try again: ");
while (getchar() != '\n'){}
}
}
So for example if first triangle's co-ordinates are (2,1), (5,6), (2,7), then I want to type in: "2 1 5 6 2 7" and as a result I want it to fill the first line of the array with the said numbers in the order I typed them in.
Obviously it doesn't work, the program stops working (not finishes the work, it stops) after the first line is given.
I get this error after debugging (after giving first line):
"Unhandled exception at 0x0FDCC28C (msvcr120d.dll) in xxx.exe: 0xC0000005: Access violation writing location 0xCCCCCCCC."
How to fix it?
You need to subtract the pointer i when detecting input error like this for example ->
#include <stdio.h>
int main(int argc, const char * argv[]) {
int tab[4][6];
for (int i = 0; i < 4; i++){
printf("Enter 6 values \n");
int retVal=scanf("%d %d %d %d %d %d", &tab[i][0], &tab[i][1], &tab[i][2], &tab[i][3], &tab[i][4], &tab[i][5]);
if (retVal == 6) {
printf("You did enter -> %d %d %d %d %d %d\n",tab[i][0],tab[i][1],tab[i][2],tab[i][3],tab[i][4],tab[i][5]);
} else {
printf("Error entering values.. (Enter numbers). \n");
while (getchar() != '\n'){}
i--;
}
}
return 0;
}
Unclear why OP's code failed without posting input used and prior code.
How to fix it?
Use fgets() to read a line of user input. Avoid mixing scanf() with fgets() in prior code. Then parse the buffer. Use " %n" at the end to look for success and extra text.
int tab[4][6];
char buf[6*12 * 2]; // Use a buffer twice expected max needs
for (int i = 0; i < 4; i++) {
while (1) {
if (fgets(buf, size buf, stdin) == NULL) {
return "Failed to read enough data"; // Handle end-of-file in some fashion
}
int n = 0;
sscanf(buf, "%d%d%d%d%d%d %n",
&tab[i][0], &tab[i][1], &tab[i][2], &tab[i][3], &tab[i][4], &tab[i][5], &n);
if (n > 0 && buf[n] == 0) {
break; // Success!
}
printf("Error - bad input, try again: ");
}
}

Reading array of integers from the first line of a text file and raising error if it exceeds 10

I've looked around and haven't seen this question answered yet. Basically I am trying to create an array of integers from text files that have sequences of integers e.g, 2 5 2 9 1 0 3 53 7 . I want to print an error message if line in the text file exceed 10 integers. There is only one line in the text file.
Here is my code so far:
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *file = fopen("somenumbers.txt", "r");
int integers[10];
int i=0;
int num;
if (file == NULL)
{
printf("Error Reading File\n");
exit (0);
}
while(fscanf(file, "%d", &num) > 0) {
integers[i] = num;
i++;
}
for (i = 0; i < 16; i++)
{
printf("Number is: %d\n\n", integers[i]);
}
fclose(file);
return 0;
}
Should I check the check the contents of the array after it is finished being created or during the initial iteration through the line? Are there any functions that would make it easy to determine if the line in the text file is larger than the limit(10)?
You must check in while loop as below;
while(fscanf(file, "%d", &num) > 0) {
if (i >= 10) {
printf("error\n");
break;
}
integers[i++] = num;
}
You should ensure that you never access integers[10], otherwise it's array out-of-bounds error which results in undefined behavior (i.e. literally anything can happen after that). So if you succeeded in reading 11-th number (which should go into integers[10]), you should stop the loop immediately.
The reason you are getting the error is the size of integers array being 10. Due to that size, if you read more than 10 integers, you will have a segment violation problem.
To find out that you have more than 10 integers, all you need to understand you should give an error is to read the 11th integer. So instead of declaring the array with size 10, switch it to 11. Then, when you read the 11th integer you may print an error message and exit properly.
Also, you may want to bound the loop printing the numbers by the amount of integers you have read.
Below is a sample code, based on yours, that implements the fixes I mentioned.
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *file = fopen("somenumbers.txt", "r");
int integers[11];
int i=0, k=0;
int num;
if (file == NULL)
{
printf("Error Reading File\n");
exit (0);
}
while(fscanf(file, "%d", &num) > 0) {
integers[i] = num;
if(k++ == 10) {
{
printf("Too many integers!!!\n"); /* or any other error message you'd like */
exit (0);
}
}
/* loop iterates until k integers are printed. k contains the # of integers read. */
for (i = 0; i < k; i++)
{
printf("Number is: %d\n\n", integers[i]);
}
fclose(file);
return 0;
}
Check before:
...
while (fscanf(file, "%d", &num) > 0) {
if (i >= 10) {
/* handle error */
break; /* or return */
}
...
to prevent trying to access an array element that does not exist
You have two errors:
1) When reading, you may write the input value outside the array boundary
2) When printing, you for sure acces outside array boundary.
Try this instead:
while(fscanf(file, "%d", &num) > 0) {
integers[i] = num;
i++;
if (i == 10)
{
break; // Can't store more value so stop the loop using break
}
}
// Save the number of values read
int total = i;
for (i = 0; i < total; i++)
// ^^^^ notice
{
printf("Number is: %d\n\n", integers[i]);
}
As an alternative to break you can put the check of i into the while condition like:
while(i < 10 && fscanf(file, "%d", &num) > 0) {
//^^^^^^ notice
integers[i] = num;
i++;
}
You have some issues with your code:
The code posted is prone to buffer overflow, as you are not checking if more than 10 integers have been found. This means you will be accessing outside the bounds of integers[10], which only causes undefined behavour.
Since you want to read one integer at a time with fscanf(), you should use:
while (fscanf(file, "%d", &num) == 1)
Instead of:
while(fscanf(file, "%d", &num) > 0)
fscanf() returns the number of values read, and using 1 instead of > 0 would make more sense in this case.
This segment here:
for (i = 0; i < 16; i++)
{
printf("Number is: %d\n\n", integers[i]);
}
is accessing beyond bounds of integers[10]. You need to change the guard so you don't exceed the limit of 10 integers.
Your code can look like this:
#include <stdio.h>
#include <stdlib.h>
#define MAXINT 10
int main(void) {
FILE *file;
int integers[MAXINT], num;
size_t count = 0;
file = fopen("somenumbers.txt", "r");
if (!file) {
fprintf(stderr, "%s\n", "Error reading file");
exit(EXIT_FAILURE);
}
while (fscanf(file, "%d", &num) == 1) {
if (count == MAXINT) {
printf("More than %d integers found!\n", MAXINT);
exit(EXIT_FAILURE);
}
integers[count++] = num;
}
printf("Success! No more than %d integers found:\n", MAXINT);
for (size_t i = 0; i < count; i++) {
printf("integers[%zu] = %d\n", i, integers[i]);
}
fclose(file);
return 0;
}

File Handling and Functions in C

I have come across the following problem.
I have a program which allows the user to create a .txt file and add up to 10 ASCII values.
I am then closing the file, and re-opening in read mode. The point of this being that I am converting the inputted ASCII to integer using ATOI.
The working code for this is provided below.
My problem is: I want to create some sort of array which stores these inputted ASCII values. BY doing so, this will enable me to call upon a function to check which of these ASCII values is smallest.
fp = fopen("c:\\CTEMP\\1.txt", "w+");
{
for (x = 0; x < 10; x++)
{
printf("\nType the word you want to add. Type exit to terminate: ");
scanf("%s", word); // word is declared as char word[10]
if (strcmp(word, "exit") == 0)
{
break;
}
fprintf(fp, "%s\n", word);
words++;
}
fclose(fp);
}
fp = fopen("C:\\CTEMP\\1.txt", "r");
while (!feof(fp))
{
fscanf(fp, "%s", &word);
number = atoi(word);
printf("\nstring is \t %s\n", word);
printf("integer is \t %d\n", number);
// location = find_minimum(array,number);
// minimum = array[location];
// printf("Minimum element location = %d and value = %d.\n", location + 1, minimum);
}
scanf_s("%d");
}
Am I tackling the problem of finding the smallest ASCII value correctly?
Is there any other way without creating another array to store the ASCII values?
As mentioned by Barmar, there is no need to store all the values in an array just for the sake of finding the minimum then. Let a variable minNr store the smallest number read so far, and let minIdx store it's index. Whenever the number read in the current pass is smaller (or equal) then minNr, adapt minNr and minIdx accordingly. Thereby, for any two equal numbers read in, the latter will be considered as the minimum's index. Note that minNr is initialized with INT_MAX, such that already the very first number read in will "beat" this initial value:
int finished = 0;
int minNr = INT_MAX;
int minIdx = 0;
fp = fopen("C:\\CTEMP\\1.txt", "r");
if (fp==NULL)
finished=1;
for (int i=1; !finished; i++)
{
char word[50];
if (fscanf(fp, "%s", word) < 1)
finished = 1;
else {
int number = atoi(word);
printf("\nstring is \t %s\n", word);
printf("integer is \t %d\n", number);
if (number <= minNr) {
minNr = number;
minIdx = i;
}
}
}
if (minIdx > 0)
printf ("min number is %d at position %d\n", minNr, minIdx);
else
printf("no numbers read in; hence: no minimum calculated.");
BTW: in your code, if word is declared as something like char word[50], then statement fscanf(fp, "%s", &word) should give you at least a compiler warning because of the superfluous &.
My problem is: I want to create some sort of array which stores these
inputted ASCII values. BY doing so, this will enable me to call upon a
function to check which of these ASCII values is smallest.
I don't know what an ASCII value is but here's how you:
char chars[10]; //create an array of 10 characters
int ints[10]; //create an array of 10 ints
char strings[10][10]; //create an array of 10 9-character strings
Am I tackling the problem of finding the smallest ASCII value correctly?
Semantically, perhaps. But you're 1) being spacially inefficient by trying to store all the elements (you probably don't need to store them -- not in memory, not on disk) and 2) you're failing to do error handling on the IO functions you call. Additionally 3) you're creating a security hole with scanf("%s", without a length limit.
Is there any other way without creating another array to store the ASCII values?
Yes. Store only your current candidate for the minimum value. The rest can be forgotten.

read a file and save as a matrix

i have a file like that :
1 100
2 200
3 300
4 400
1
i want to save it as a matrix and i want to save NULL if there is no second number !
i tried to write the program but it does not work correctly !
#include<stdio.h>
int main() {
int k=0 ,i,j , arr[100][100];
FILE *in= fopen("file.txt","r");
char line[1000];
while(fgets(line,1000,in) !=NULL) k++;
fgets(line,1000,in);
for (i=0;i<k;i++){
for (j=0;j<2;j++){
int tmp ;
fscanf(in ,"%d", &tmp) ;
arr[i][j] = tmp ;
}
}
fclose(in);
return 0; }
Two major problems:
The first is that the first loop will read all lines, even the one with the single number on the line. That means the lonely fgets call will not do anything, and more importantly that the value of k will be wrong.
The second problem is that once you read all data from the file, you don't go back to the beginning of the file, instead you continue to try and read from beyond the end of the file.
The first problem can be solve by skipping the second fgets call, and decreasing k by one.
The second problem can be solved by calling rewind after you counted the number of lines.
Also when you actually read the numbers, you don't need the inner loop, just do e.g.
scanf("%d %d", &arr[i][0], &arr[i][1]);
Actually, you don't need the first line-counting loop at all, you can do it all in a single loop, by using fgets and sscanf and then checking the return value of sscanf. So your program could look something like
#include <stdio.h>
int main(void)
{
int values[100][2];
FILE *input = fopen("file.txt", "r");
size_t entries = 0;
if (input != NULL)
{
char buffer[40];
while (fgets(buffer, sizeof(buffer), input) != NULL && entries < 100)
{
int res = sscanf(buffer, "%d %d", &values[entries][0], &values[entries][1]);
if (res <= 1 || res == EOF)
{
// Read the last line with only one number, or an error happened
values[entries][0] = 0;
values[entries][1] = 0;
break;
}
++entries;
}
if (ferror(input))
{
printf("Error reading file\n");
}
fclose(input);
}
// All done, the number of "records" or "entries" is in the variable entries
// Example code: print the values
for (size_t i = 0; i < entries; ++i)
printf("Line %d: %d %d\n", i + 1, values[i][0], values[i][1]);
return 0;
}

Why is my program crashing when I debug?

I've started to write a program that reads and stores team info and stores in a structure, reorders and prints results.
First i'm trying to read team names and stores them in a member in a structure, then read team scores and store them in another member.
However, as soon as i debug the file, it crashes. It doesn't even start correctly. I get this error
Unhandled exception at 0xFEFEFEFE in PA2.exe: 0xC0000005 Access
violation executing location 0xFEFEFEFE.
I've backtracked enough to figure out that it is somewhere in the while loop but can't figure out what's wrong with it.
I am using visual studio 2012 and i get no errors when i build it.
#include "stdafx.h"
#include "string.h"
#include <stdio.h>
struct team
{
char name[20];
int no_games;
int points;
int goals_scored;
int goals_let;
};
int main(void)
{
FILE *input2a;
FILE *input2b;
int error1;
int error2;
int i;
char team1_name[20];
char team2_name[20];
int team1_goals;
int team2_goals;
struct team teamlist[20];
error1 = fopen_s(&input2a, "C:\\Users\\New PC\\Desktop\\input2a.dat", "r");
i = 0;
while (i < 20)
{
i ++;
fscanf_s(input2a, "%s", teamlist[i].name);
}
error2 = fopen_s(&input2b, "C:\\Users\\New PC\\Desktop\\input2b.dat", "r");
while (fscanf_s(input2b, "%s %d %s %d", team1_name, &team1_goals, team2_name, &team2_goals) !=EOF)
{
if (team1_goals < 0)
{
printf("Team %s has negative goals - Invalid entry\n", team1_name);
}
else if (team2_goals < 0)
{
printf("Team %s has negative goals - Invalid entry\n", team2_name);
}
else
{
}
}
return 0;
}
From only looking at the while loop: you write to memory out of bounds.
struct team teamlist[20];
And in the while:
i = 0;
while (i < 20)
{
i ++;
fscanf_s(input2a, "%s", teamlist[i].name);
}
So you enter the while when i=19 and increase it to 20 which makes it out of the bounds for the array.
The problem is here (see my comment):
i = 0;
while (i < 20)
{
i ++; // was 19, become 20, but maximal allowed value is 19
fscanf_s(input2a, "%s", teamlist[i].name);
}
The name of this problem is ABW (array bounds write). It means, that your program writes outside array (it happens when i==19, so the condition of the loop i < 20 is satisfied, but right after it you increase it: i++). To fix it you need just to swap two lines of the body of this loop:
{
fscanf_s(input2a, "%s", teamlist[i].name);
i++;
}
And much better and simplier it would be to use for loop here:
for (i = 0; i < 20; i++)
fscanf_s(input2a, "%s", teamlist[i].name);
And the last fix: now there is still possible ABW error. The reason of it is simple: size of teamlist[i].name is 20. So, if input file contains long lines, your program will write outside this array. To fix it you can extend "%s this way (we have here "19" instead of "20" because last character is '\0'):
for (i = 0; i < 20; i++)
fscanf_s(input2a, "%19s", teamlist[i].name);
And one more thing about fscanf_s(): this function shall return the number of successfully matched and assigned input items. So in the second loop it is better to check, that it returns 4.
Update:
If nothing happens, let's open documentation:
Unlike scanf and wscanf, scanf_s and wscanf_s require the buffer size
to be specified for all input parameters of type c, C, s, S, or string
control sets that are enclosed in []. The buffer size in characters is
passed as an additional parameter immediately following the pointer to
the buffer or variable. For example, if you are reading a string, the
buffer size for that string is passed as follows:
char s[10];
scanf_s("%9s", s, _countof(s)); // buffer size is 10, width specification is 9
So in your case in means, that first loop should be corrected this way:
for (i = 0; i < 20; i++)
fscanf_s(input2a, "%19s", teamlist[i].name, _countof(teamlist[i].name));
And you need the same fix for next call of fscanf_s in the second loop, because there are two "%s"s in that call.

Resources