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.
Related
I was working on the following 2d-array program to output this result shown in picture:
I can't seem to get the min value for the result and get it displayed in array form.
The code is below:
#include<stdio.h>
#define NUMROWS 2
#define NUMCOLS 3
//accessing elements of 2D array using pointers
int main(void){
const int table[NUMROWS][NUMCOLS]={{1,2,3},{5,6,7}};
int minvals[NUMROWS];
int i, j;
int *ptr = &table;
//accessing the elements of 2D array using ptr
printf("table values: min value\n");
for(int i=0;i<NUMROWS;i++){
for(int j=0;j<NUMCOLS;j++)
printf("%d ",*((ptr+i*NUMCOLS)+j));
printf("\n");
}
for(int i=0;i<NUMROWS;i++){
for(int j=0;j<NUMCOLS;j++)
printf("%d ",*((ptr+i*NUMCOLS)+j)<minvals[i]);
}
return 0;
}
The existence of minvals would imply that you are expected to calculate the minimum value of each 'row' of table before then moving on to printing. As it stands, had your program properly calculated the minimum values of each array, your printing would be rather out of order.
There's no need to do any tricky, manual pointer manipulation. Simple array subscription is much clearer.
Let's start simple and return to basics by looking at the way we find the minimum value in a one dimensional array, as it is the core of this problem.
To find the minimum value in an array we need a few things to start:
An array
The length of the array
An initial value to compare against
The array itself is obviously each subarray of table, and the length in this case is known to be NUMCOLS. Our initial value should either be INT_MAX (or another type-appropriate maximum constant found <limits.h>), such that every element in the array is equal to or less than our initial value, or a value from the array itself.
Often times we opt for the second option here, choosing the first element in the array as our initial value, and comparing it to the second and onward elements.
As such, finding the minimum value in a single 'row' would look like this
const int row[NUMCOLS] = { 9, 2, 5 };
int min = row[0];
for (int i = 1; i < NUMCOLS; i++)
if (row[i] < min)
min = row[i];
but since we want to find and record the minimum value of each 'row' in table, we're going to use a nested loop. Instead of the min variable from before, we store each value in the associated index of our minvals array.
for (i = 0; i < NUMROWS; i++) {
minvals[i] = table[i][0];
for (j = 1; j < NUMCOLS; j++)
if (table[i][j] < minvals[i])
minvals[i] = table[i][j];
}
When it comes time to print, we're going to repeat our nested loop. Our inner loop prints each element of each 'row' of table, and we end each iteration of the outer loop by printing the value found in minvals with the same index of our 'row'.
for (i = 0; i < NUMROWS; i++) {
for (j = 0; j < NUMCOLS; j++)
printf("%6d", table[i][j]);
printf(":%6d\n", minvals[i]);
}
Here's a working example.
#include <stdio.h>
#define NUMROWS 2
#define NUMCOLS 3
int main(void) {
const int table[NUMROWS][NUMCOLS] = {
{ 9, 2, 5 },
{ 3, -4, -12 }
};
int minvals[NUMROWS];
int i, j;
for (i = 0; i < NUMROWS; i++) {
minvals[i] = table[i][0];
for (j = 1; j < NUMCOLS; j++)
if (table[i][j] < minvals[i])
minvals[i] = table[i][j];
}
puts("Table value: minimum values");
for (i = 0; i < NUMROWS; i++) {
for (j = 0; j < NUMCOLS; j++)
printf("%6d", table[i][j]);
printf(":%6d\n", minvals[i]);
}
}
A good further exercise for you would be to compose the logic of the inner loop for finding minimum values into a more generic function. Its function signature would look like
int min(int *array, size_t length);
allowing it to work on arrays of varying sizes. Then our outer loop could be as simple as:
for (i = 0; i < NUMROWS; i++)
minvals[i] = min(table[i], NUMCOLS);
The line
int *ptr = &table;
is wrong, because &table is of type int (*)[2][3] (i.e. a pointer to the entire table), whereas ptr is a pointer to a single element. Also, your pointer is non-const, so it cannot point be made to point into a const array.
If you want ptr to point to a single int value, then you should declare it the following way:
const int *ptr = &table[0][0];
Also, you are reading the contents of the array minvals, although that array contains uninitialized data. This does not make sense and causes undefined behavior.
Instead of doing complex pointer arithmetic with the expression
*((ptr+i*NUMCOLS)+j))
you can simply write the following:
table[i][j]
That way, you do not need the pointer ptr and your code is simpler.
Given the code:
int vector[5] = {1, 2, 3, 4, 5};
int *pv = vector, value = 3;
for(int i = 0; i < 5; i++) {
*pv++ *= value;
}
for(int i = 0; i < 5; i++) {
printf("%d, ", *(pv+i));
}
I expect each individual element of the array pointed to by pv to be multiplied by 3.
Instead what I get as an output is:
32766, -1554513907, -527290408, -333409024, 32766,
What am I doing wrong?
The problem is that you incremented the pointer in the first for cycle in every loop, so when you get to the end of it, pv is already pointing to one past the end of vector.
For that reason all the values printed in the second for cycle represent residual values stored in addresses out of the bounds of the array, classic undefined behavior.
A quick fix would be to reset the pointer in between the two cycles:
for (int i = 0; i < 5; i++){
*pv++ *= value;
}
pv = vector; //here
for (int i = 0; i < 5; i++) {
printf("%d, ", *(pv + i));
}
Or use the iterator i in both cycles, since you already have it in the for, you might as well use it:
for (int i = 0; i < 5; i++){
pv[i] *= value;
}
for (int i = 0; i < 5; i++) {
printf("%d, ", pv[i]);
}
With this method the pointer is not incremented, it's always pointing to the beginning of the array, accessing its indexes is safe.
Note that I used array notation [] as it's slightly less cluttered than the pointer dereference notation.
In your program, the first for loop (ie)
for(int i = 0; i < 5; i++) {
*pv++ *= value;
}
Here, pointer(pv) gets incremented for 5 times and when the control exits the loop , pointer(pv) is now pointing to something which is out-of-bounds of your array size(vector)
Since you're using the same pointer variable in second for loop to print the array(vector) values, the garbage values gets printed.
You can solve this by reassigning your pointer variable(pv) back to the 1st position of your array either by
pv= vector;
// or
pv = &vector[0];
before your second for loop.
So I have a 2D array that I want to use later. Right now I just want to fill the empty spots.
So far I've just been messing around with array types and different default values. From my understanding a new array is filled with '0', I have tried NULL aswell.
int r = 5;
int c = 5;
int i;
int j;
int k = 0;
int area = r*c;
const char *array[r][c]; //tried char array[r][c] and other types
Setup my initial values and array here.
while(k< area){
for (j = 0; j < c; j++){
for (i = 0; i<r; i++){
if (array[i][j] == 0){
board[i][j] = ".";
}
printf("%c",aray[i][j]);
if (i = r - 1){
printf("\n");
}
k++;
}
}
}
This is where I try replacing all non filled values (all of them at this point) with ".", so the output should be a row of 5x5 dots. Instead I get weird letters and numbers. I have tried %s insead of %c, and no luck there but the output was different. Where I do %s I get some dots, but still not on a grid and the weird values show up.
Also Im pretty sure printf in a for loop, by default does it on a new line so I won't get the grid, so is there a better way of doing this?
What you have is an array of pointers. This would be suitable for a 2D array of strings, but not for a 2D array of characters. This isn't clear from your question, so I'll assume that you actually want a 2D array of characters. The syntax is: char array [r][c];.
Notably, since you used r and c which are run-time variables, this array is a variable-length array (VLA). Such an array cannot be placed at file scope ("global"). Place the array inside a function like main().
In order to use VLA you must also have a standard C compiler. C++ compilers and dinosaur compilers won't work.
Since you will have to declare the VLA inside a function, it gets "automatic storage duration". Meaning it is not initialized to zero automatically. You have to do this yourself, if needed: memset(array, 0, sizeof array);. But you probably want to initialize it to some specific character instead of 0.
Example:
#include <stdio.h>
#include <string.h>
int main (void)
{
int r = 5;
int c = 5;
char array [r][c];
memset(array, '#', sizeof array);
for(size_t i=0; i<r; i++)
{
for(size_t j=0; j<c; j++)
{
printf("%c", array[i][j]);
}
printf("\n");
}
}
Output:
#####
#####
#####
#####
#####
From my understanding a new array is filled with '0'
const char *array[r][c];
No*, you have fill it yourself in a double for loop, like this:
for(int i = 0; i < r; ++i)
for(int j = 0; j < c; ++j)
array[i][j] = 0
since your structure is a variable sized array.
Instead I get weird letters and numbers
This happens because your code invokes Undefined Behavior (UB).
In particular, your array is uninitialized, you then try to assign cells to the dot character, if their value is already 0.
Since the array is not initialized, its cells' values are junk, so none satisfied the condition of been equal to 0, thus none was assigned with the dot character.
You then print the array, which still contains garbage values (since it was never really initialized by you), and the output is garbage values.
* As stated by #hyde, this is true for local non-static arrays (which is most probably your case). Statics and globals are default initialized (to zero if that was the case here).
You have several problems:
You are declaring a pointer to the array you want, not the array
Whenever R and C are not compile time known, you can't use a built in array. You might can however use VLAs (C99 as only C standard has VLAs mandatory, C11 made them optional again), which seems like a built in array with a size not known at compile time, but has very important implications, see : https://stackoverflow.com/a/54163435/3537677
Your array is only zero filled, when declared as a static variable.
You seem to have mistake the assign = operator with the equal == operator
So by guessing what you want:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define R 5
#define C 5
int r = R;
int c = C;
int i;
int j;
int k = 0;
int area = R*C;
const char array[R][C];
int main() {
while(k< area){
for (j = 0; j < c; j++){
for (i = 0; i<r; i++){
if (array[i][j] == 0){
}
printf("%c",array[i][j]);
if (i == r - 1){
printf("\n");
}
k++;
}
}
}
//or
char** dynamic_array = malloc(r * c);
if (dynamic_array == NULL) {
perror("Malloc of dynamic array failed");
return EXIT_FAILURE;
}
memset(dynamic_array, '0', r*c);
k = 0;
while(k< area){
for (j = 0; j < c; j++){
for (i = 0; i<r; i++){
if (dynamic_array[i][j] == 0){
}
printf("%c",dynamic_array[i][j]);
if (i == r - 1){
printf("\n");
}
k++;
}
}
}
return 0;
}
I'm trying to write a program that analyzes a (3 x 4) matrix of strings provided by the user. Ultimately, it needs to output the longest string present in the matrix, along with that string's length.
My program seems to read the input correctly, as judged its success in echoing back the input strings, but it does not correctly output the longest word. I'm sure I'm committing some kind of pointer-related error when I pass the value of longest word, but I do not have any idea how to solve it.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define M 4
#define N 5
#define MAX_DIM 20
void findMAX(char matrice[N][M][MAX_DIM]) {
char maxr;
int index;
int i, j, it;
index = 0;
maxr = *(*(*(matrice+0)+0)+MAX_DIM);
for (i = 0; i < N-1; i++) {
for (j = 0; j < M-1; j++) {
if (index < strlen(matrice[i][j])) {
index = strlen(matrice[i][j]);
// I save the longer line's value
it = i;
// I save the maximum's value
maxr = *(*(*(matrice+i)+j)+MAX_DIM);
}
}
}
printf ("The MAX is: -/%s/- and it's long: -/%d/- \n", maxr, index);
printf ("It is content in the: %d line, which is: \n", it);
for (j = 0; j < N-1; j++) {
printf("%s ", matrice[it][j]);
}
}
void leggi(char matrice[N][M][MAX_DIM]) {
int i, j;
for (i = 0; i < N-1; i++) {
for (j = 0; j < M-1; j++) {
printf ("Insert the element matrix [%d][%d]: ", i, j);
scanf ("%s", matrice[i][j]);
fflush(stdin);
}
}
}
void stampa(char matrice[N][M][MAX_DIM]) {
int i, j;
printf("\n(4 x 3) MATRIX\n");
for (i = 0; i < N-1; i++) {
for (j = 0; j < M-1; j++) {
printf("%s ", matrice[i][j]);
}
printf("\n\n");
}
}
int main(int argc, char *argv[]) {
char matrix[N][M][MAX_DIM]; //Matrix of N*M strings, which are long MAX_DIM
printf("************************************************\n");
printf("** FIND THE LINE WITH THE MAXIMUM ELEMENT **\n");
printf("** IN A (4 x 3) MATRIX **\n");
printf("************************************************\n");
printf ("Matrix Reading & Printing\n");
leggi (matrix);
stampa (matrix);
findMAX(matrix);
return 0;
}
First of all to address some misconceptions conveyed by another answer, consider your 3D array declared as
char matrix[N][M][MAX_DIM];
, where N, M, and MAX_DIM are macros expanding to integer constants.
This is an ordinary array (not a variable-length array).
If you want to pass this array to a function, it is perfectly acceptable to declare the corresponding function parameter exactly the same way as you've declared the array, as indeed you do:
void findMAX(char matrice[N][M][MAX_DIM])
But it is true that what is actually passed is not the array itself, but a pointer to its first element (by which all other elements can also be accessed. In C, multidimensional arrays are arrays of arrays, so the first element of a three-dimensional array is a two-dimensional array. In any case, that function declaration is equivalent to both of these:
void findMAX(char (*matrice)[M][MAX_DIM])
void findMAX(char matrice[][M][MAX_DIM])
Note in particular that the first dimension is not conveyed. Of those three equivalent forms, I find the last clearest in most cases.
It is quite odd, though, the way you access array elements in your findMAX() function. Here is the prototypical example of what you do:
maxr = *(*(*(matrice+i)+j)+MAX_DIM);
But what an ugly and confusing expression that is, especially compared to this guaranteed-equivalent one:
maxr = matrice[i][j][MAX_DIM];
Looking at that however, and it how you are using it, I find that although the assignment is type-correct, you are probably using the wrong type. maxr holds a single char. If you mean it to somehow capture the value of a whole string, then you need to declare it either as an array (into which you will copy strings' contents as needed), or as a pointer that you will set to point to the string of interest. The latter approach is more efficient, and I see nothing to recommend the former for your particular usage.
Thus, I think you want
char *maxr;
... and later ...
maxr = matrice[0][0];
... and ...
maxr = matrice[i][j];
That sort of usage should be familiar to you from, for example, your function stampo(); the primary difference is that now you're assigning the expression to a variable instead of passing it directly to a function.
And it turns out that changing maxr's type that way will correct the real problem here, which #AnttiHaapala already pointed out in comments: this function call ...
printf ("The MAX is: -/%s/- and it's long: -/%d/- \n", maxr, index);
requires the second argument (maxr) to be a pointer to a null-terminated array of char in order to correspond to the %s directive in the format string. Before, you were passing a single char instead, but with this correction you should get mostly the expected result.
You will probably, however, see at least one additional anomaly. You final loop in that function has the wrong bound. You are iterating with j, which is used as an index for the second dimension of your array. That dimension's extent is M, but the loop runs to N - 1.
Finally, I should observe that it's odd that you allocate space for a 5 x 4 array (of char arrays) and then ignore the last row and column. But that's merely wasteful, not wrong.
Try something like this:
void findMAX(char matrice[N][M][MAX_DIM]){
// char maxr
char maxr[MAX_DIM];
int index;
int i, j, it;
index = 0;
// maxr = *(*(*(matrice+0)+0)+MAX_DIM);
strncpy(maxr, *(*(matrice+0)+0), MAX_DIM);
for (i = 0; i < N-1; i++)
{
for (j = 0; j < M-1; j++)
{
if (index < strlen(matrice[i][j]))
{
index = strlen(matrice[i][j]);
it = i;
// maxr = *(*(*(matrice+i)+j)+MAX_DIM);
strncpy(maxr, *(*(matrice+i)+j), MAX_DIM);
}
}
}
printf ("The MAX is: -/%s/- and it's long: -/%d/- \n", maxr, index);
printf ("It is content in the: %d line, which is: \n", it);
// for (j = 0; j < N-1; j++){
for (j = 0; j < M-1; j++){
printf("%s ", matrice[it][j]);
}
}
It's possible to pass multi-dimensional arrays to C functions if the size of the minor dimensions is known at compile time. However the syntax is unacceptable
void foo( int (*array2d)[6] )
Often array dimensions aren't known at compile time and it is necessary to create a flat array and access via
array2D[y*width+x]
Generally it's easier just to use this method even if array dimensions are known.
To clarify in response to a comment, C99 allows passing of variable size arrays using the more intuitive syntax. However the standard isn't supported by Microsoft's Visual C++ compiler, which means that you can't use it for many practical purposes.
What I mean by my question is that if I have a nested for loop like
for(int i = 0; i < 10; i++)
{
for(int j = 0; j < 10; i++)
{
printf("%d\n"___);
}
}
What would I put in the blank? Would [i][j] be illegal if I declared an array already?
I am not sure what exactly you are stuck on based on your question so I made a minimal C program with comments
I declared an int array who's first and second dimension are at least 10 because you iterate both i and j from 0 to 9 (inclusive). This is to avoid out of bounds problems while iterating
The array's elements are not initialized in the program. It is possible that this program will print all zeros when you run it. It is also possible that it prints other values that happened to be in memory (because the array values are not initialized)
Last I declared i and j outside the for loop just in case this was the problem you were facing
#include <stdio.h>
int main(int argc, char** argv) {
// Declare an array
// Note that both dimensions are at least 10
// Also note that none of the values are initialized here
int myArray[10][10];
// Both i and j are declared here rather than in the for loop
// This is to avoid the following potential error:
// error: 'for' loop initial declarations are only allowed in C99 or C11 mode
int i, j;
for (i = 0; i < 10; i++) {
for (j = 0; j < 10; j++) {
// Note that the values this prints are uninitialized
printf("%d\n", myArray[i][j]);
}
}
return 0;
}
Your question was really unclear. But from what I understand is you have some 2-d array, and you want to print contents of array.
You must have arrary already defined as int arr[10][10], then you can use,
printf("%d\n", arr[i][j]);