Is this implementation of insertion in array incorrect? - c

I was reading a tutorial at tutorialspoint.com for Data Structures.
In the section about the array data structure is this implementation of insertion an element in an array, which is accesing an element outside of the bound of the array :
int LA[] = {1,3,5,7,8};
int item = 10, k = 3, n = 5;
int i = 0, j = n;
printf("The original array elements are :\n");
for(i = 0; i<n; i++) {
printf("LA[%d] = %d \n", i, LA[i]);
}
n = n + 1;
while( j >= k){
LA[j+1] = LA[j];
j = j - 1;
}
LA[k] = item;
printf("The array elements after insertion :\n");
for(i = 0; i<n; i++) {
printf("LA[%d] = %d \n", i, LA[i]);
}
Is'nt accesing an element outside of the bounds of an array undefined behaviour and therefore very bad practice?
If so why is this given in a tutorial?

Is'nt accesing an element outside of the bounds of an array undefined behaviour
Yes. Good spotting.
and therefore very bad practice?
I can't argue with that, except maybe to say that it's a little understated. A program that exhibits UB is flat wrong.
If so why is this given in a tutorial?
I can only speculate, but that section of the tutorial is not only wrong, but altogether poorly conceived. C arrays have fixed length, therefore you cannot "insert" into a C array in any sense that preserves all the values that already were there. (I disregard dynamic memory approaches, which are not relevant to the code presented.)
You can use code similar to that presented in the example if you adjust it to avoid reading or writing past the end of the array. Such an approach to "inserting" an element must lose the element originally at the array's end.

Of course it's a bad practice. When you try to do
while( j >= k){
LA[j+1] = LA[j];
j = j - 1;
}
... you will have LA[6] receiving a value when LA has size 5. Then an error message will be shown and at some moment the execution will be aborted. Besides that the exit status (echo $?) will be different of zero, i.e., it is saying that your program wasn't finished with successful.

Related

How to order a list of integers from greatest to least?

I have an assignment where I must use a structure to put in student information. I must then order the credit hours from greatest to least. I am focused on the integer ordering loop, I just can't figure out why my program is outputting incorrectly.
#include <stdlib.h>
#include <stdio.h>
struct Student {
char name[21];
int credits;
} s[99];
int main()
{
int students;
int tempCred = 0;
char tempName[21];
printf("How many students?: ");
scanf_s("%d", &students);
for (int i = 0; i < students; i++)
{
printf("\nStudent Name?: ");
scanf_s("%s", &s[i].name, 21);
printf("\nCredits Taken?: ");
scanf_s("%d", &s[i].credits);
}
for (int i = 0; i < students; i++) {
for (int j = 0; j < students; j++) {
if (s[j].credits > tempCred) {
tempCred = s[j].credits;
s[i].credits = s[j].credits;
s[j].credits = tempCred;
}
}
printf("\n%d", s[i].credits);
}
}
For example, if I were to enter 2,6, and 8 when asked for credit hours, the program would output '8,6,8'. I am not unfamiliar with sorting, but for some reason something isn't making sense when I look at this code. Could anyone help me order the integers from greatest to least? Thanks!
NOTE: I am aware there are better ways to do this, but my professor is making us use strictly C, no C++ at all. I just need help ordering the integers.
There are various techniques used for sorting. For instance the bubble sort, quick sort, insertion sort, etc. The simplest one is the bubble sort - but it's not the most efficient one.
In your program you have an array of structs. You've done the inserting part of the structs into the array and that's fine. The problem lies in the second part - the sorting. You have a for loop that starts at the very first element (i.e. 0) and goes all the way up to the last element (i.e. students-1). And nested inside this loop is another for loop - that also has the same range???
No, that's wrong. Instead replace the first and second for loops with this:
for (int i = 0 ; i < students-1 ; i++)
{
for (int j = i+1 ; j < students ; j++)
{
...
}
}
Here, the outer for loop begins with element 0 and goes up to the element before the last. The inner for loop starts with the next element to what the outer for loop stores (i.e. j = i + 1). So if i = 0, j = 1. And this loop goes all the way up to the last element of the array of structs.
Now, inside the inner for loop specify the condition. In your case you want them sorted in descending order (highest to lowest) of the credits.
for (int i = 0 ; i < students-1 ; i++)
{
for (int j = i+1 ; j < students ; j++)
{
if(s[j].credits > s[i].credits) // then swap the credits
{
tempCred = s[j].credits ;
s[j].credits = s[i].credits ;
s[i].credits = tempCred ;
}
}
}
Note that j is one greater that i. So if i = 0, j = 1, then the if statement reads
If the credits held in the struct in element 1 of the array is greater than the credits stored in the struct in element 0 of the array, then...
If the condition is met, the credits in these 2 structs are swapped.
This an implementation of the "bubble sort". See this for more techniques and explanations.
Finally, you can display the credits:
for(int index = 0 ; index < students ; index++)
{
printf("\n%d", s[index].credits) ;
}
Like a lot of people in the comments have said, use debugger. It'll help you trace the logic of your programs.
Like #Barmar said use the qsort() function from glibc.
Not only is easier than writting your own method but it is much faster at O(N log N) on average.

What should I do with unhandled exception

I tried a lot of things to do but it still show me the same, that there is unhandled exception: access violation writing location in VS. But it doesn't happen when i sorting 1d array. What can I try next?
int main(void) {
static int a[3][4]{}, ab[3][4]{};
int i, j, k, N, M;
int* a1=nullptr;
printf("Matrica mora da ima velicinu 3 sa 4\n");
printf("Enter the order \n\n\t");
scanf_s("%d%d",&N ,&M);
for (i = 0;i < M;++i)
{
for (j = 0;j < N;++j)
{
scanf_s(" %d", &a[i][j]);
ab[i][j] = a[i][j];
}
printf("\n");
}
for (i = 0;i < M;++i) {
for (j = 0;j < N;++j) {
printf(" %d", a[i][j]);
}
printf("\n ");
}
//classic sorting
for (i=0; i < M; ++i)
{
for (j = 0;j < N;++j)
{
for (k = j + 1;j < N;++k)
if (a[i][j] > a[i][k])
{
*a1 = a[i][j]; // there is exception thrown
a[i][j] = a[i][k];
a[i][k] = *a1;
}
}
}
First off, there is a problem with static allocation of arrays, but there is no sanitization of N and M after the user inputs them. That means that you allocate only a matrix of 3x4, but the user can input and write to a matrix of any dimensions (e.g. 10x10), which could lead to access violation.
I'd recommend either having sanitation of the input values, e.g.
// It's always better to have limits as constant.
const int MAX_N = 3;
const int MAX_M = 4;
static int a[MAX_N][MAX_M];
...
scanf_s("%d%d",&N ,&M);
// Check if the dimensions can be fitted into the statically allocated array.
if(N > MAX_N || N <= 0 || M > MAX_M || M < 0)
{
// indicate invalid dimensions, either by returning from main with -1
// or calling exit(-1), or throwing an exception.
return -1;
}
In case the input didn't exceed 3x4, another thing that could be problematic - i goes from 0 to M, not N (what I would expect), which could also be problematic. The way matrix addressing works in C/Cpp is that the matrix is linearized into an array, and accessing it with a[i][j] leads to accessing the array with a[i*MAX_J + j]. In your case, the array has 12 elements (3x4), and MAX_J=4, so accessing it with a reverse set of indexes a[4][3] will access a[4*4+3]=a[19], which will access memory from outside of the array.
On the access violation writing problem, a1 isn't allocated, so when you try do execute *a1= ... you are writing to nullptr, which is a protected address, hence the access violation when writing. The way to solve this is either to:
have a1 be a int variable (not a pointer)
first allocate memory for a1 by executing a1 = malloc(sizeof(int)); and then freeing it after use with free(a1) (but since it's only a single element, I'd recommend converting a1 to int instead)
assign the address of the matrix element like a1=&a[i][j], but that would not be valid logically in your case (after that, you write into the location the pointer is pointing to, so the original value will be lost).
The reason why it's not happening for the 1d array is probably because of the inverted dimensions - the matrix would probably be 1x4, but you will be accessing it as 4x1, and you are sorting all the values with j index from 0 to 1, and since there is only one value you would not enter the k loop.

C: pointers to arrays, and destructive sorting

I wrote a brief piece of code. It has two functions: bubbleSort is a bubble sorting function (smallest to largest), and "int main" is used to test this piece of code with an int array of size 5.
I'd like this to destructively sort the array, and not simply pass through a copy. I have looked and looked, but I am still not entirely clear how this should work. What am I missing here?
#include <stdio.h>
void bubbleSort(int values[], int n);
int main(void) {
//set simple test array to make sure bubbleSort works
int arr[5] = {5,4,3,2,1};
//run it through function, and then print the now sorted array to make sure
bubbleSort(arr, 5);
printf("%i", arr);
return 0;
}
void bubbleSort(int values[], int n)
{
for (int i = 0; i < n; i++) {
for (int j = 0, hold = 0; j < n-i; j++) {
if (values[j] > values[j+1]) {
hold = values[j+1];
values[j+1] = values[j];
values[j] = hold;
}
}
}
return;
}
Note: The rest of my code looks sound to my amateur coding mind, but please give me pointers on what i can improve, what can be better, etc. I thought about using recursion for the bubble sort but i'm not yet as comfortable with C as I'd like to be to implement that. However if you have suggestions i'll be more than happy to read them.
thanks!
Looks like your function is sorting the array (although with some bugs) and you are just printing the result incorrectly. printf doesn't know how to print arrays. Instead, you need to use a loop to print each integer one at a time:
for(int i=0; i<5; i++){
printf("%d ", arr[i]);
}
printf("\n");
After changing this, the output is 1 2 3 4 5, as expected.
However, as mentioned in the comments, there are some bugs in the implementation of the bubblesort. For example, it tries to read elements from indedex after the end of the array, which is undefined behavior (namely, j+1 can be 5, which is out of bounds). I would recommend checking your book again to get a correct implementation of bubblesort.
There is one issue in you bubble sort code which must be fixed. Your inner loop has the issue:
/* for (int j = 0, hold = 0; j < n-i; j++) { */ // ISSUE here
for (int j = 0, hold = 0; j < n-i-1; j++) { // j < n-i-1 should be the condition
This is becasue, take the case of when i = 0, i.e. the first iterartion of outer for loop. This time, j < n - i will be true when j is one less than n - which is the last index of your array. Then you do comaprision between values[j] and values[j+1], where values[j+1] is clearly out of bound of your array. This will invoke undefined behavior, and your function will not give deterministic results.
Next improvement could be that your outer loop only needs to iterate from i = 0 till i < n-1, i.e. one times less than the total elements. You are interating one time more than needed.
Third, you can use a flag to keep track of weather you swap at least once in your inner loop. If there there are no swaps in inner loop then it means that array is already sorted. So at the end of each iteration of inner loop you can see if any swap was done, and if no swaps were done then break out of the outer loop. This will improve performance in cases where array is already almost sorted.
void bubbleSort(int values[], int n)
{
int swap; // To use as a flag
// for (int i = 0; i < n; i++) {
for (int i = 0; i < n-1; i++) {
swap = 0; // set swap flag to zero
// for (int j = 0, hold = 0; j < n-i; j++) {
for (int j = 0, hold = 0; j < n-i-1; j++) {
if (values[j] > values[j+1]) {
hold = values[j+1];
values[j+1] = values[j];
values[j] = hold;
swap = 1; // swap was done
}
}
if (swap == 0) // If no swap was done
break; // Means array already sorted
}
return;
}
And, although not related to your sorting function, as others have pointed out, printf("%i", arr); is wrong, and will invoke undefined behavior because you are using a wrong format specifier in printf. It seems like you are trying to print the array. For that you can do:
// printf("%i", arr);
for (int i = 0; i < 5; i++)
printf("%d ", arr[i];)
printf("\n");
Your code already sorts the array in-place - although there is a bug in it. I'll address the subject of the question only (in-place sorting of an array in C) as comments have already highlighted the bugs with the sort function.
The print-out of the result is incorrect though as it tries to print the arr pointer as an integer:
sort.c:10:18: warning: format specifies type 'int' but the argument has type 'int *' [-Wformat]
printf("%i", arr);
~~ ^~~
1 warning generated.
However changing this to:
for (int i = 0; i < 5; i++)
printf("%i", arr[i]);
fixes the problem with the output.
Perhaps your confusion comes from how arrays are actually a syntactic way to access pointers in C. arr is a pointer. arr[1] is the same as *(arr + 1) (the contents of the pointer arr + 1 using pointer arithmetic, which increments the pointer by the sizeof the type). So when you pass arr into the function, you are passing a pointer to the existing array, then you are modifying its contents, sorting the array in-place.

Global alignment using affine gap penalty function

I have to write a program that does global alignment between two sequences using affine gap penalty function. The dynamic algorithm (modified Needleman Wunsch) calculates similarity (maximum score that express how similar sequences are) of two given sequences, s and t. And it takes into account gaps, blocks of consecutive spaces in a sequence, which are more likely to occur then isolated spaces, by building three 2d arrays. The arrays could be not so formally described as:
array C: keeps maximum score for blocks that end with a character of sequence s aligned with a character of sequence t;array BS: keeps maximum score for blocks that end with a character of sequence t aligned with a space in sequence s
array BT: keeps maximum score for blocks that end with a character of sequence s aligned with a space in sequence t;
The algorithm has the following recurrence relation:
C[i,j] = v(s[i],t[j]) + max{C[i-1][j-1], BS[i-1][j-1], BT[i-1][j-1]}
BS[i,j] = max{C[i][j-1]-(h+g), BS[i][j-1]-g, BT[i][j-1]-(h+g)}
BT[i,j] = max{C[i-1][j]-(h+g), BS[i-1][j]-(h+g), BT[i-1][j]-g}
** v(s[i],t[i]) = value of match(when both character are identical) or mismatch(when characters are not identical)
Similarity is the highest value among the last value of each array. The problem is when I run the program it has a strange behaviour:
For a given pair of sequences, my program gives different values for the same pair of sequences if I change which one is t or s. So, could you please help me to find out why the program has such behaviour? Do you have any idea of what I'm doing wrong? And about the code, here it goes:
int main (void){
int mat, mis, h, g,
sim, i, j, m, n;
/* mat = match, mis = mismatch, h = open gap penalty, g = extend gap penalty */
string s, t;
s = malloc(1500);
t = malloc(1500);
scanf("%d %d %d %d", &mat, &mis, &h, &g);
scanf("%s", s);
scanf("%s", t);
m = strlen(s);
n = strlen(t);
int C[m][n], BS[m][n], BT[m][n];
C[0][0] = 0;
for(j = 1; j<= n; j++)
C[0][j] = -32000;
for(i = 1; i<= m; i++)
C[i][0] = -32000;
for(j = 1; j <= n; j++)
BS[0][j] = -(h + g*j);
for(i = 0; i <= m; i++)
BS[i][0] = -32000;
for(j = 0; j <= n; j++)
BT[0][j] = -32000;
for(i = 1; i <= m; i++)
BT[i][0] = -(h + g*i);
for(i = 1; i <= m; i++){
for(j = 1; j <= n; j++){
C[i][j] = align(s[i-1],t[j-1],mat,mis) + max(C[i-1][j-1],BS[i-1][j-1],BT[i-1][j-1]);
BS[i][j] = max((C[i][j-1]-(h+g)),(BS[i][j-1]-g),(BT[i][j-1])-(h+g));
BT[i][j] = max((C[i-1][j]-(h+g)),(BS[i-1][j]-(h+g)),(BT[i-1][j]-g));
}
}
printf("\n");
printf("c[m][n]: %d bs[m][n]:%d bt[m][n]: %d\n", C[m][n], BS[m][n], BT[m][n]);
sim = max(C[m][n], BS[m][n], BT[m][n]);
printf("sim: %d\n", sim);
return 0;
}
Ok, I finally find out the problem after trying many printfs, since I don't know how to use debuggers.The first clue I had was the segmentation fault that gcc was telling me when I tryed to read the sequences (with a relatively big length) from files. It's true that segmentation fault can have several causes, but almost all the times I saw this error in my programs, it occured because I was trying to access a position that actually didn't exist in the array.
Then the many printfs showed some values in the initialization step, which were different from what the first row and first column of each array should have. I associated the segmentation fault with the strange values from initialization step, and decided to check the declaration step of the arrays as well as all loop conditions. There it was! I simply forgot a very basic feature of any array: if the array has size n, you can access from zero to n-1. To solve my very newbie error, I added one position for row and column in each array (since the position (0,0) is not associated with any pair of aligned characters) so that each array has size [m][n], where m is the (length + 1) of sequence s, and n is the (length+1) of sequence t. Furthermore, I altered all loop conditions to access till [m-1][n-1] position. Now the program works fine.

Iterate ALL the elements of a circular 2D array exactly once given a random starting element

We are given a 2-dimensional array A[n,m] with n rows and m columns and an element of that array chosen at random R.
Think of the array as being circular in that when we visit A[n-1, m-1] the next element we visit would be A[0, 0].
Starting with element R, we want to visit each element exactly once and call function foo() before moving to the next element.
The following is my first implementation but there is a bug. The bug being that if we start at row x somewhere between 0 and n-1, we will not visit element from 0 to x-1 in that column.
// Init - pretend rand() always returns valid index in range
curr_row = rand();
curr_col = rand();
// Look at each column once
for (int i = 0; i < m; ++i)
{
for (; curr_row < n; ++curr_row)
{
foo(A[curr_row][curr_col]);
}
curr_row = 0;
curr_col = (curr_col + 1) % m;
}
What is a clean way to do this traversal such that we meet the above requirements?
Just move to the next index, and check whether you are back at the start, in which case, stop:
// should be something that guarantees in-range indices
curr_row = rand();
curr_col = rand();
int i = curr_row, j = curr_col;
do {
foo(A[i][j]);
++j;
if (j == n) {
j = 0;
++i;
if (i == m) {
i = 0;
}
}
}while(i != curr_row || j != curr_col);
This doesn't do what your implementation does, but what the question title asks for.
quite rusty with c , but it should be the same:
// Init - pretend rand() always returns valid index in range
curr_row = rand();
curr_col = rand();
//first row
for(int j=curr_col;j<m;++j)
foo(A[curr_row][j]);
//rest of the rows
for(int i=(curr_row+1)%n;i!=curr_row;i=(i+1)%n)
for(int j=0;j<m;++j)
foo(A[i][j]);
//first row , going over missed cells
for(int j=0;j<curr_col;++j)
foo(A[curr_row][j]);
if you care a lot about performance , you can also divide the second loop so that there won't be a "%" at all .
another alternative , since C has 2d arrays in a simple array:
// Init - pretend rand() always returns valid index in range
curr_row = rand();
curr_col = rand();
int start=curr_row*m+curr_col;
int maxCell=n*m;
int end=(start-1)%maxCell;
for(int i=start;i!=end;i=(i+1)%maxCell)
foo(A[i]);
foo(A[end]);
could have a tiny math bug here and there ,but the idea is ok.
A[curr_row, curr_col] is not the syntax used to access a member of a multidimensional array; instead, you want A[curr_row][curr_col], assuming the array was declared correctly. A[curr_row, curr_col] will invoke the comma operator, which effectively computes the first value, then throws it away and calculates the second value, then indexes the array with that value.

Resources