What makes a program not follow the loop condition? - c

Just a basic program, written by a newbie. Supposed to read in values into a dynamic array, then print them out in reverse order. You can't input the size of array beforehand, the array's size will adjust as long as inputs aren't terminating characters.
I think I wrote it okay, but there are errors about dereferencing pointers and when I run it in VS, it won't even register inputs. When attempted in other compiler, it does register the input, but doesn't terminate with "-1".
Thinking about it, looking it up, I don't notice my mistake, hope you will help me.
Edit: thanks for pointing out the semicolon after while, but now it's a "Heap Corruption Error" after inputting 2 or 3 inputs. What went wrong?
int i=0;
int *p, *a;
int n=1;
p = (int*)malloc(n * sizeof(int));
printf("Enter integers here, and input -1 when done:\n");
while (p[i] != -1);
{
scanf_s("%d", &p[i]);
n = i + 1;
a= (int*)malloc(n * sizeof(int));
for (int j = 0; j < n; ++j)
{
a[j] = p[j];
}
free(p);
p = NULL;
p= (int*)malloc(n * sizeof(int));
for (int k = 0; k < n; ++k)
{
p[k] = a[k];
}
free(a);
a = NULL;
++i;
}
--i;
if (i <= 0)
{
printf("%d", p[i]);
--i;
}
free(p);
p = NULL;

while (p[i] != -1);
remove the trailing ;.
Also malloc gives you uninitialized memory, so chances are that the condition is not true at the first iteration. You probably want a do { ... } while(...); loop.

Reformatting your code reveals the (or at least a) bug:
int i = 0;
int *p, *a;
int n = 1;
p = (int *)malloc(n * sizeof(int));
printf("Enter integers here, and input -1 when done:\n");
while (p[i] != -1)
;
{
scanf_s("%d", &p[i]);
// ...
There's a stray semicolon after the first while, making it an infinite loop of nothing.

Related

stack corruption by eliminate a printf()

some time ago I tried to program a Mergesort. In some point I got an error that I was able to solve, but still saved the code because have something strange that i don't understand. The code is the following:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef int elem;
void mergesort(elem * arr, unsigned n){
if(n != 1){
if(n == 2){
if(arr[0] > arr[1]){
int change = arr[0];
arr[0] = arr[1];
arr[1] = change;
}
}else{
unsigned i = 0, j = 0, mit = (n+1)>>2, fin = n>>2;
elem * arr_2 = (elem *)malloc(sizeof(elem) * n), * mit_arr = arr+mit;
mergesort(arr, mit);
mergesort(mit_arr, fin);
while(i < mit || j < fin){
if(arr[i] <= mit_arr[j]){
arr_2[j+i] = arr[i];
i++;
}else{
arr_2[j+i] = mit_arr[j];
j++;
}
}
for(i=0; i<n; i++)
arr[i] = arr_2[i];
free(arr_2);
}
}
}
int main(){
unsigned a = 10;
int i;
elem * arr = (elem*)malloc(sizeof(elem) * a);
arr[0] = 12;
arr[1] = 3;
arr[2] = -3;
arr[3] = 22;
arr[4] = 12;
arr[5] = 11;
arr[6] = 4;
arr[7] = 9;
arr[8] = 10;
arr[9] = 2;
printf("something\n"); // 1
mergesort(arr, a);
printf("\n");
for(i=0; i<a; i++){
printf("%d, ", arr[i]);
}
printf("\n");
free(arr);
return 0;
}
The thing is that, despite the fact that the code doesn't do what I want and it seems like there is no error, if I comment out the line marked by 1 (printf("something\\n"); ) then the error "malloc(): corrupted top size" appears. I actually don't know why something like that is possible, so I came here to see if someone have an explanation.
I tried to debug the program with gdb and got the same error, but have more information:
Program received signal SIGABRT, Aborted.
__GI_raise (sig=sig#entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
50 ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
but still without idea of what happened.
There are a couple of major issues with your code. These are things you should be able to test yourself by checking whether the values being used by your function are what you expect.
Here's the first issue. You have calculated the length of the first half of the array as (n+1)>>2, and then you assume the length of the remaining array is n>>2. That is simply not true. Shifting a value to the right by 2 binary places is a division by four.
It is far better to use "normal" math instead of attempting to be clever. This reduces the chance for errors, and makes your code easier to read.
unsigned mit = n / 2, fin = n - mit;
The other issue is your merge. You have made your while-loop run until both i and j are out-of-range. But in your loop, it's guaranteed that on at least one of the iterations, one of those values will be out-of-range.
A better way to merge arrays uses three loops. The first one runs until either of the arrays has been merged in, and the remaining two loops will copy the remaining part of the other array.
unsigned x = 0, i = 0, j = 0;
while(i < mit && j < fin){
if(arr[i] <= mit_arr[j]){
arr_2[x++] = arr[i++];
}else{
arr_2[x++] = mit_arr[j++];
}
}
while(i < mit){
arr_2[x++] = arr[i++];
}
while(j < fin){
arr_2[x++] = mit_arr[j++];
}

Stuck in a for loop entering values to an array in C language

I am trying to practice with C by making a bubble sort program. The problem until now seems to be that the for loop that is giving values to the cells of the array is stuck after the condition is no longer fulfilled but it doesn't seem to be executing the commands in the loop. I don't know what is happening exactly and I have added some extra lines to see what is happening an these were my conclusions. Here is the code:
#include <stdio.h>
#include <stdlib.h>
void swap(int *x, int *y)
{
int temp = *x;
*x = *y;
*y = temp;
}
int *sort(int *array)
{
int finish = 1;
while (finish = 1)
{
finish = 0;
for (int i = 0; i <= sizeof(array); i++)
{
if ((array + i) > (array + i + 1))
{
swap(array + i, array + i + 1);
finish = 1;
}
}
}
return array;
}
int main()
{
int s, res;
printf("Give me the size of the array being sorted(larger than 1) : ");
do
{
res = scanf("%d", &s);
if (res != 1)
{
printf("Wrong Input!\n");
exit(1);
}
if (s < 2)
printf("Only numbers equal or larger than 2\n");
} while (s < 2);
int array[s];
for (int i = 0; i < s; i += 1)
{
scanf("%d", array + i);
printf("%d %d %d\n\n", *(array + i), i, i < s); // I used this to check if my values were ok
}
printf("end of reading the array"); //I added this line to see if I would exit the for loop. I am not seeing this message
sort(array);
printf("\n");
for (int i = 0; i < sizeof(array); i++)
printf("%d\n\n", array + i);
printf("Array has been sorted! Have a nice day!\n\n************************************************************");
return 0;
}
See the annotations in the code:
#include <stddef.h> // size_t 1)
#include <stdio.h>
#include <stdlib.h>
void swap(int *x, int *y)
{
int temp = *x;
*x = *y;
*y = temp;
}
int *sort(int *array, size_t size) // needs an extra parameter to know the size of the array
{
int finish = 1;
while (finish /* = 1 * you don't want assignment, you want comparison: */ == 1)
{
finish = 0;
for (int i = 0; i /* <= sizeof(array) */ < size - 1; i++) // i should be of type size_t
{
// if ((array + i) > (array + i + 1)) you are not dereferencing:
if(array[i] > array[i + 1])
{
// swap(array + i, array + i + 1); // easier to read imho:
swap(&array[i], &array[i + 1]);
finish = 1;
}
}
}
return array; // why does this function return anything? it is never used.
}
int main()
{
int s; /* , res; no need for an extra variable res */
printf("Give me the size of the array being sorted(larger than 1) : ");
do
{
// res = scanf("%d", &s);
// if (res != 1)
if (scanf("%d", &s) != 1)
{
printf("Wrong Input!\n");
// exit(1); // should be EXIT_FAILURE. Use return instead of exit() when in main().
return EXIT_FAILURE;
}
if (s < 2)
printf("Only numbers equal or larger than 2\n");
} while (s < 2);
int array[s];
for (int i = 0; i < s; /* i += 1* idiomatic: */ ++i) // size_t would be the correct type for s and i.
{
scanf("%d", /* array + i use indexes: */ &array[i]);
printf("%d %d %d\n\n", array[i], i, i < s); // again: indexes. i < s is allready ensured by the condition of the for-loop
}
printf("end of reading the array");
// sort(array); // sort will have no idea about the size of array use
sort(array, s); // instead.
printf("\n");
for (int i = 0; i < /* sizeof(array) 2) */ s; i++)
printf("%d\n\n", /* array + i * again you don't dereference */ array[i]);
printf("Array has been sorted! Have a nice day!\n\n************************************************************");
return 0;
}
1) size_t is the type that is guaranteed to be big enough to hold all sizes of objects in memory and indexes into them. The conversion specifier for scanf() is "%zu".
2) sizeof(array) in main() will yield the number of bytes in array, but you want the number of elements so you'd have to use sizeof(array) / sizeof(*array). But thats not needed since you already know its size. It is s.
This line
printf("end of reading the array");
has no line feed at the end of the string. This is a problem because printf is part of the family of functions called "buffered IO". The C library maintains a buffer of the things you want to print and only sends them to the terminal if the buffer gets full or it encounters \n in the stream of characters. You will not see, end of reading the array on your screen until after you have printed a line feed. You only do this after calling sort(). So all you know is your program is getting into an infinite loop at some point before the end of sort.
So there are actually three loops that could be infinite: the for loop you identified, the while loop in sort and the for loop inside the while loop. As the other answers point out, you have made the classic mistake of using assignment in the while conditional
while (finish = 1)
// ^ not enough equals signs
Unless your C compiler is really old, it is probably outputting a warning on that line. You should heed warnings.
Also, you should learn to use a debugger sooner rather than later. Believe me, it will save you a lot of time finding bugs.
In the sort function sizeof(array) returns the size of the pointer. (you can check it by yourself using printf("%d", sizeof(array).
The solution is to change your function to:
int sort(int* array, size_t size) { ... }
and call it with the correct array size:
sort(array, s);

How do we correctly dynamically allocate memory multiple times?

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#define MAX_STRING_SIZE 20
int main() {
/* Enter your code here. Read input from STDIN. Print output to STDOUT */
int N, Q;
int i, j, k, l, m, x;
char **str;
scanf("%d\n", &N);
str = (char **)malloc(sizeof(char *) * N);
for(i = 0; i < N; i++){
str[i] = malloc(MAX_STRING_SIZE * sizeof(char));
scanf("%s",str[i]);
}
printf("%d\n",N);
for(j = 0; j < N; j++){
printf("%s",str[j]);
printf("\n");
}
scanf("%d",&Q);
printf("%d\n",Q);
char **qry_str;
qry_str = (char **)malloc(sizeof(char *) * Q);
for(l = 0; l < Q; l++){
qry_str = malloc(MAX_STRING_SIZE * sizeof(char));
scanf("%s",qry_str[l]);
}
for(m = 0; m < N; m++){
printf("%s",qry_str[m]);
printf("\n");
}
for(k = 0; k < N; k++)
free(str[k]);
free(str);
for(x = 0; x < N; x++)
free(qry_str[x]);
free(qry_str);
return 0;
}
I am new to programming, and I am trying to allocate memory for two 2d strings using malloc function, but when I try to input data for the second string qry_str, (null) appears on the screen, and the program exits.
My question is:
How do we dynamically allocate memory for 2D arrays in C multiple times?
Do I need to free the memory first before using it again? (Though when I try to do that it causes segmentation fault error.)
Is this the problem due to my compiler? (I am using gcc.)
In your second case, you're overwriting qry_str inside the loop, which is not what is intended. You most probably want
for(l = 0; l < Q; l++){
qry_str[l] = malloc(MAX_STRING_SIZE * sizeof(char));
scanf("%s",qry_str[l]);
}
That said, a few suggestion:
You don't need four separate counters i, j, l, m. The first clause of for statement re-assigns the counter to 0 anyway, even if you reuse only one.
sizeof(char) is gurantted to be 1 in C. Instead, you should consider writing the statements like
qry_str[l] = malloc(MAX_STRING_SIZE * sizeof *qry_str));
to make them more robust.
Always check for the return values for scanf() family to ensure success.

2 Dimensional Array sorting in c

Here is a segment of my (incomplete) code
int rows(int board[][9]){
int badUnits = 0, i = 0, n = 9, j, z = 0;
int (*temp)[9];
//Sort each row of 2d array
for (z; z < n; z++){
for (i; i < n; i++){
for (j = i; j < n; j++){
if (board[z][i] > board[z][j]){
temp = board[z][i];
board[z][i] = board[z][j];
board[z][j] = temp;
}
}
}
}
printf ("%d\n", temp[1][0]);
printf ("%d\n", temp[1][1]);
return badUnits;
}
The function takes a 9*9 array.
I get a segmentation fault when the print statements are executed.
I believe my sort code is correct because it is similar to what I use for 1d arrays and I think everything else is correctly assigned.
So the culprit would be my temp variable. I have gone through and tried to assign values to it, tried to change the type, and have taken into account that the 2d array decays into a pointer but is not actually a pointer.
The conclusion I am left with is that this is a dynamic allocation issue. Can someone please lend a hand and assist me in fixing this? I have exhausted my knowledge base and am stuck.
To clarify: I decided to print the temp variable because I thought it would lend some information. The main problem was that the swap was not working, and I was still left with an unsorted array when I originally attempted to print out the board[][]. I know that board is what I am SUPPOSED to be printing.
Thank you for any help!
You assign an int value to temp
temp = board[z][i]; // Temp now is a what ever value was at
// That location in the array e.g. 42
You then treat temp as if it was the address in memory of an integer array
temp[1][1] // treat temp as a pointer and find the integer
// 10 integers further along then temp.
Also sometime temp will not have been initialised (never assigned to) in this case your going to get unexpected behaviour depending on what the last value stored where temp is now (Lets call it a random number).
Did you mean to output the values in board?
printf ("%d\n", board[1][0]);
printf ("%d\n", board[1][1]);
One thing to notice is that the variable temp will only get assigned to if a swap occurs, if the sorting algorithm was correct that is still a situation that could occur with a input corresponding to a sorted board.
But more importantly, the variable temp is used as an int during the swap. Later that integer value is interpreted as a pointer in the expressions temp[1][0] and temp[1][1], which in all likelihoods is not a valid address. You may want to change temp to be declared as:
int temp;
And figure out exactly what you would like to print. If it is whatever one of the two swapped values was (for the last swapped pair in the loop), then you would print it as:
printf("%d", temp);
Else, you would have to add logic according to what you really want to do.
Note that a single pass of this algorithm would not perform a complete sort, but I guess that's one of the reason why you said the provided code was not complete.
Something like this?
#include <stdio.h>
#include <stdlib.h>
void printArray(int** arr, int w, int h) {
for (int i = 0; i < w; ++i) {
for (int j = 0; j < h; ++j) {
printf("%d ", arr[i][j]);
}
printf("\n");
}
}
void sortArray(int** arr, int w, int h) {
for (int row = 0; row < h; ++row) {
for (int col = 0; col < w; ++col) {
for (int i = 0; i < w; ++i) {
if (arr[row][i] > arr[row][col]) {
int tmp = arr[row][col];
arr[row][col] = arr[row][i];
arr[row][i] = tmp;
}
}
}
}
}
int main() {
int w = 9, h = 9;
int** arr = (int**)malloc(sizeof(int*) * w);
for (int i = 0; i < w; ++i) {
arr[i] = (int*)malloc(sizeof(int) * h);
for (int j = 0; j < h; ++j) {
arr[i][j] = rand() % 10;
}
}
printf("Unsorted:\n");
printArray(arr, w, h);
sortArray(arr, w, h);
printf("Sorted:\n");
printArray(arr, w, h);
for (int j = 0; j < h; ++j) {
free(arr[j]);
}
free(arr);
return 0;
}

Generate int of numbers between 1 and n with dynamic n

I am struggling with an algorithm to print numbers between 1 and a dynamic variable n into an int.
int n = // dynamic value
int i = 0;
int output[n];
for(i = 0; i < n; i++) {
output[i] = i;
}
However, as n is dynamic, the code won't compile.
Any help would be much appreciated - thanks in advance.
You need to allocate a buffer, or dynamic-sized array, with malloc:
int n = // whatever
int i = 0;
int* output = NULL;
// Allocate the buffer
output = malloc(n * sizeof(int));
if (!output) {
fprintf(stderr, "Failed to allocate.\n");
exit(1);
}
// Do the work with the array
for(i = 0; i < n; i++) {
output[i] = i;
}
// Finished with the array
free(output);
output is a pointer to the beginning of the buffer you allocated, and you can treat it as an array of n ints.
When you're finished with the array, you need to de-allocate the memory with free.
This should work:
int n = // whatever
int i = 0;
int* output = (int*)malloc(sizeof(int)*n);
for(i = 0; i < n; i++) {
output[i] = i;
}
Don't forget to free(output); when you don't need it anymore.
EDIT: Made it C.
If 'n' is changing during runtime, then you could use malloc like suggested in the comments. Then check if you need more space, then automatically realloc more space should it be needed

Resources