Explanation of output of this C code - c

Here is my code:
#include <stdio.h>
#include <stdlib.h>
int main()
{
void check(int n, int arr[]);
int arr[] = {1, 2, 3, 4};
int i;
check(4, arr);
for (i = 0; i < 4; i++) {
printf("%d\n", arr[i]);
}
return 0;
}
void check(int n, int arr[]) {
int i = 0;
int *p = 0;
while (i++ < n)
p = &arr[i];
*p = 0;
}
I need an explanation for the output.
The original question I was asked, and the expected multiple-choice answers, are:

Please post your actual code, not what you intended to type. Actually copy-paste your real code.
Because you typed it in wrong.
You either put extra {} in here:
while(i++ < n) {
p = &arr[i];
*p = 0;
}
or you used a comma instead of a semicolon:
while(i++ < n)
p = &arr[i],
*p = 0;
and so the assignment to zero ran every time.
Edit to add: Yep, you put extra {} which the original question didn't have. So in your code, the "*p = 0" executes every time round the while loop, whereas the original question the "*p = 0" only executes once and clobbers some random data that is one past the end of the array.
(By the way, the answer to the original question is actually "it is undefined behaviour; the program doesn't necessarily print anything. Valid behaviours include printing 1 2 3 4, printing 42 42 42 42, crashing, and formatting your hard drive.")

I'm not sure what choices you're talking about, however the cause of your output is here:
int i=0;
int *p=0
while(i++<n)
{
p=&arr[i];
*p=0;
}
Variable 'i' starts at 0 but you increment it before entering the loop so the first index of the array is ignored. You then set a pointer to array index 'i' and then immediately dereference the pointer and set the value to 0;
Because of this any array you pass will always retain its first value whilst every other value will be zero.
if you want to include the first index of the array you'd be much better off doing:
for (int i = 0; i < n; ++i)
{
// stuff
}
With this, 'i' is not incremented until after the code between the braces has been executed.

In check(), i gets incremented after the comparison, but before the first statement inside. So the zero (first) element of the array is never set to 0, like the rest are. arr's 1 stays 1, and 2, 3, & 4 each become 0.
EDIT:
The OP code has changed since the version I discussed. It's a whole new problem now.

Some things you should know.
First:
you should declare your functions if you declare/define them after main.
Second:
when you declare an Array, the array starts from 0 to n and not from 1 to n.
So, if you declare int arr = {1,2,3,4} then you have arr[0],1,2,3 and not arr[1],2,3,4.
Third:
you should avoid code like:
while (i++ < n) {
p = &arr[i];
*p = 0;
}
And use:
while (i < n) {
p = &arr[i];
*p = 0;
i++;
}
Fourth:
What exactly did you expected from this:
int *p = 0;
Anyway, you just try to access a memory location that not belong to you.

Related

Error expected identifier or '(' int &arrayreturn[I] = {I}

#include "stdio.h"
int printsomething(int *array, int arrayreturn[5]) {
int i;
for(i = 0; i < 10; ++i) {
printf("%d\n", array[i]);
}
for(i = 0; i < 5; ++i) {
int &arrayreturn[i] = {i};
}
return 0;
}
int main() {
int array[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
// int *arraypointer = &array;
int arrayp[5];
int i;
printsomething(array, arrayp);
for(i = 0; i < 5; ++i) {
printf("%d\n", arrayp[i]);
}
return 0;
}
I am learning C and right now just playing with arrays and pointers trying to get comfortable. This bit of code has the goal of passing an array to a function, which was successful before I added the second part. That second part being assigning values in the called function to an already initialized array. Since we can't directly return an array I understood this was the way to do it. What exactly do you all think is going wrong here? And I just completely off the target?
If you want to assign values to the array elements you need to use [] to access the elements and = to assign them. I cannot really explain your code because it is unclear how you came to the conclusion that you need to write int &arrayreturn[i] = {i};. Your loop can be this:
for(i = 0; i < 5; ++i) {
arrayreturn[i] = i;
}
the first problem is that when you have a parameter of the form int arrayreturn[5] you actually just pass an int pointer not an entire array of 5 elements. int arrayreturn[5] and int *arrayreturn compile to exactly the same cpu instructions. I never use the int arrayreturn[5] syntax because i think it is confusing so i rather just pass a pointer and this is common practice as far as i know.
secondly in the second part of your code you try to declare a new array of size i by calling int &arrayreturn[i] = {i} this is not possible because of multiple reasons mostly because you cant dynamically allocate arrays on the stack. it should be arrayreturn[i] = i

C stack smashing detected in array

I am trying to solve a question.
If in array a number is duplicated I make him 0. My code is throwing an error could you please help me ?
#include <stdio.h>
int main() {
int a[] = {-3, -2, -1, -7, -3, 2, 3, 4, 2, 7, 10, 3};
int length = 12;
int zero_duplicates(int laenge, int *a) {
int zero[] = {};
int k = 0;
int j = 1;
for(int x=0; x<laenge; x++)
{
if (zero[*a] == 1) {
*a = 0;
} else {
zero[*a] = 1;
k++;
}
a++;
}
return k;
}
int count = zero_duplicates(length, a);
printf("%d -- ", count);
for(int i = 0; i < length; i++) printf(" %i ", a[i]);
return 0;
}
This ...
int zero[] = {};
... is not a valid array declaration in C. If your compiler accepts it as an extension then it ought at least to be emitting a warning, and even then it probably doesn't mean what you think it means. Specifically, among the most likely extensions would be to interpret that as declaring a zero-length array (which also would constitute an extension), such that accessing any element overruns the array bounds.
Moreover, no matter how long the array is, if any of the elements of the input array are negative (as is the case in the example) then zero[*a] will constitute an out-of-bounds access when a points to one of those elements.
Overall, you need a different approach. What you're trying to do is not viable.
As a separate matter, C does not support nested functions, so your code is relying on yet another extension in that respect. This particular issue can be resolved by lifting the nested function out of main(), however, putting it above instead of inside.

How to get top indices of float array in C and pairing it with strings stored in an another array

I updated the code to find top 5 indices of a float array. Some
how it is only updating top[0]th element for max indices. In the
mentioned example below max indices is like below top[0] = 9, top[1]
=7, top[2]=5 and so on. But it is updating top[0] only.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
int main() {
double *arr =malloc(sizeof(double)*10);
int N=10;
int n =5;
int *top =malloc(sizeof(int)*10);
arr[0] = 0.123;
arr[1] = 0.345;
arr[2] = 0.445;
arr[3] = 0.545;
arr[4] = 0.645;
arr[5] = 0.745;
arr[6] = 0.542;
arr[7] = 0.945;
arr[8] = 0.145;
arr[9] = 0.995;
int top_count = 0;
int i;
for (i=0;i<N;++i) {
// invariant: arr[top[0]] >= arr[top[1]] >= .... >= arr[top[top_count-1]]
// are the indices of the top_count larger values in arr[0],...,arr[i-1]
// top_count = max(i,n);
int k;
for (k=top_count;k>0 && arr[i]>arr[top[k-1]];k--);
// i should be inserted in position k
if (k>=n) continue; // element arr[i] is not in the top n
// shift elements from k to top_count
printf("6:: Iam here\n");fflush(stdout);
int j=top_count;
if (j>n-1) { // top array is already full
j=n-1;
} else { // increase top array
top_count++;
}
for (;j>k;j--) {
top[j]=top[j-1];
}
// insert i
top[k] = i;
printf("top[%0d] = %0d\n",k,top[k]);
printf("top_count=%0d\n",top_count);
}
return top_count;
}
int top_elems(double *arr, int N, int *top, int n);
int top_count = top_elems(&output, 10, top,5);
output already decomposes to double * do you are passing the address_ of a pointer to double into a function that should take a pointer to double
top is not initialised before the function call so is undefined the first use of it dereferences this undefined pointer
... yeah, I'm not going to go further. your code has some serious but simple to spot issues. If you had made a MCV example, you should have seen some of of them, instead of just dumping your code here.
After code changes:
I updated question to update the top five indices of float array into top[] array. but it is only updating top[0]th element. anything wrong with the code?
Well, I updated the indentation of the code in the question to make it more readable.
You will notice that there is no indentation after this for loop:
for (k=top_count;k>0 && arr[i]>arr[top[k-1]];k--);
This is because the loop body of this loop is:
;
That's it. it is just an empty statement that does nothing. All the loop does is set variables, which are then modified in the rest of the code that follows, but as they are not within a loop, they are only executed the once.
As the loop goes from top_count down to 0, it should be obvious why it is just the first index that is modified.

Integer Pointer Array

I have started an introductory class to C. I cannot explain the output that I get from running the code below
./a.out 6
Output is:
Array A elements: 0 1 2 3 4 5
Array B elements: 1 2 3 4 5 796830176
What I think the code is doing:
When manup_array is executed, each value of the respective pointers will be incremented, but since it is post-fix, this takes effect only later on after the original value is returned.
True enough, when we print array A first, we get 0 1 2 3 4 5 (i.e. before incrementation).
Subsequently when we print array B, the incrementation takes effect, so we get 1 2 3 [...]
What really puzzles me is why the last number is 796830176. Also, running this on various computers produces a different last number every time, suggesting that the pointer addressing is somehow responsible for this.
Could someone explain this to me?
Note:
The outputs of each array are identical (1 2 3 4 5 6) if I use the pre-fix operator. This is consistent with what I think is going on -> the pointers don't change; only the values get updated.
#include <stdio.h>
#include <stdlib.h>
void manup_array(int *array[], int n); // Forward declaration.
int main(int argc, char *argv[])
{
// The size N of 2 arrays are the same; obtain them from cmd line.
int N = atoi(argv[1]); // Convert from str to int in C.
int arrayA[N]; // Declare integer array.
int *arrayB[N]; // Declare integer pointer array.
for (int i = 0; i < N; i++)
{
arrayA[i] = i;
arrayB[i] = &arrayA[i]; // Assign address of each element in A to element in B.
}
manup_array(arrayB, N);
printf("Array A elements: ");
for (int i = 0; i < N; i++)
{
printf("%d ", arrayA[i]);
}
printf("\n");
printf("Array B elements: ");
for (int i = 0; i < N; i++)
{
printf("%d ", *arrayB[i]);
}
printf("\n");
return 0;
}
void manup_array(int *array[], int n) { // Take in B as input, then increase each elem by 1
for (int i = 0; i < n; i++)
{
*array[i]++;
}
}
This is really obscure code. What is does:
The function takes an array of pointers as parameter. Since the parameter to the function had type int *array[], any change of the items of array will affect the caller and alter arrayB.
The interesting part of the function is *array[i]++;. The operator precedence rules in C state that [] has higher prio than postfix ++, which has higher prio than unary *.
Since array is an array of pointers, array[i] gives you a pointer. Not a the value it points at. Then ++ increments the pointer to point at the next item in the arrayA of main.
And then finally there is a * which takes the contents of what that pointer pointed at, and then does nothing with them. The * is superfluous and just there to confuse the reader.
So back in main, you have changed all the pointers of arrayB. arrayB[0] now points at arrayA[1] and so on. The last item of arrayB will point one item past the end of arrayA, so for the last item, you access the array out-of-bounds and get a garbage value.
void manup_array(int *arr[], int n) { // Take in B as input, then increase each elem by 1
for (int i = 0; i < n; i++)
{
int val = (*arr[0]); // get the value pointed to by the current value of arr
val++; // increment it
*(arr[0]) = val; // assign it back
arr++; // increase the pointer
}
}
Incredibly obtuse, but it demonstrates what you mean to do and how your obscure code muddled up the operators.
To add, makes debugging way easier!
manup_array() increments the pointer, not the value as expected.
Modified manup_array().
void manup_array(int *array[], int n) { // Take in B as input, then increase each elem by 1
for (int i = 0; i < n; i++)
{
//*array[i]++;
(*array[i])++;
}
}
I suggest to refer Pointer Arithmetic: ++*ptr or *ptr++?

C For Loop Not Working?

I'm working with strings in C as character arrays, and I'm trying to ensure that I can dynamically pass values into my for loops.
The following code works, no problem:
for (int i = -6; i < 11; i++) {
int test = OverlapStrength(fragments[1], fragments[2], i, 0);
printf("%d\n", test);
}
In fact, this code works, too:
for (int i = -strlen(fragments[2]) + 1; i < 11; i++) {
int test = OverlapStrength(fragments[1], fragments[2], i, 0);
printf("%d\n", test);
}
But for some reason, this code doesn't print ANYTHING:
for (int i = -strlen(fragments[2]) + 1; i < strlen(fragments[1]); i++) {
int test = OverlapStrength(fragments[1], fragments[2], i, 0);
printf("%d\n", test);
}
I have checked the values for both -strlen(fragments[2]) + 1 and strlen(fragments[1]) just before the loop and they check out to -6 and 11 respectively. Clearly the loop works when I place those values directly into their places, but when I replace the second one with the strlen calculations, it breaks and I can't figure out why for the life of me. Help?
Edit
OverlapStrength takes its arguments as constants so I can't change them, so I'm pretty sure I'm not changing the fragments as I go. Here's the method declaration:
int OverlapStrength(const char one[], const char two[], int startOne, int startTwo)
The contents of the fragments shouldn't be important, but they're simply strings that I'm trying to piece back together from overlapping fragments. I have already checked that my fragments are all coming out properly and that their lengths are computed properly when done outside of declaring this loop.
strlen returns value of type size_t, which is probably a typedef for unsigned int for your case. Then you are comparing a signed int (i) and unsigned int (strlen(...)). C decides then to cast your signed value to an unsigned type (because of default type promotions). -6 converted to unsigned int is 4294967290, therefore your comparison is false, so the loop ends.
To fix this, you can for example cast strlen to a signed value, e.g.:
i < (int) strlen(fragments[1])
In a for-loop, the codition (the i < strlen(fragments[1]) part) gets evaluated on every iteration. If OverlapStrength changes the value of fragments[1] to something less than i, the loop will abort.
To fix this, use a constant:
int loopUntil = strlen(fragments[1]);
for (int i = -strlen(fragments[2]) + 1; i < loopUntil; i++) {
int test = OverlapStrength(fragments[1], fragments[2], i, 0);
printf("%d\n", test);
}

Resources