I was given the assignment of writing a C code which contains a function, which when passed through an array of length n returns a pointer to the array’s largest element. In order to make it easy for us, the length n was set to 10.
I wrote the code below and compiled it and it didn't show any error. Then, I ran this code and it asked for the 10 inputs for the array, but instead of returning the pointer with the largest element, it read segmentation fault 11.
I am new to pointers, and so could not figure out what exactly went wrong. Any help will be greatly appreciated.
#include<stdio.h>
#define N 10
int *find_largest(int a[], int n)
{
int i;
int *max;
*max = a[0];
for(i = 1; i < n; i++)
{
if(a[i] > *max)
*max = a[i];
}
return max;
// this function returns the pointer with the max. value
}
int main(void)
{
int b[N], i;
int *p;
printf("Enter %d numbers: ", N);
for(i = 0; i < N; i++)
scanf("%d", &b[i]);
//scans all the inputs
p = find_largest(b, N);
//p gets assigned the value of the max valued pointer
printf("largest element: %d", *p);
return 0;
}
Edit- After looking at the wonderful advices given, I modified my code a bit. I changed *max=a[0] to max= &a[0], and *max=a[i] to max=&a[i]. Now, the code runs without any error, but instead of returning the pointer with the largest value, it returns the largest input instead.
In this line, you write to the place the uninitialised ponter is pointing to.
*max = a[0];
This causes undefined behaviour (or "UB", reading up on it is worth the time) and to be strictly avoided; among other reasons because it is a very likely reason for segfaults.
What you probably want to do is to write the address of the first element into the pointer.
max = &a[0];
Later you write the place the pointer is pointing to, updating it to the max value you have found.
*max = a[i];
Guessing from the rest of your code, you probably want to just keep the address of the max element, so that you can return its address as it is in the input array, without changing the values in the input array (which your currently do, and it seems unlikely that you intend to...).
max = &a[i];
Referring to your comment (that the value is returned, not the pointer):
For returning a pointer (not a value), make sure that you
return max; // the pointer, not the value it is pointing to
Which is what you actually do in the currently shown code version (possibly before an edit...).
Do not return *max; that would return the value.
If by "return" you mean "print", then you need to change the
printf("largest element: %d", *p);
Use p instead of *p and change the format specifier accordingly.
You probably want "largest element at address: %p". (Compare http://en.cppreference.com/w/c/io/fprintf )
printf("largest element at address: %p", p);
int *max;
*max = a[0];
This is UB (undefined behavior) since max is not pointing to valid memory and you try to dereference it.
max = &a[0];
Moreover your logic to find the max is wrong. Why do you reset it every time to 0th element. It should be something like.
for(i = 1; i < n; i++)
{
if(a[i] > *max)
max = &a[i];
}
Related
For an project assignment, I have this following variable from an prototype function which is not allocated.
int **suff;
This variable will receive a pointer to an array (int *) from a function which will generated an array of (int) from a FILO list (file).
(p is just a content structure, p->suff is a file)
int t = file_size(p->suff);
/* Prototype of file_tabint is
* int * file_tabint(file *p, int * psize)
*/
// Assign the generated array to the *suff)
*suff = file_tabint(p->suff, &t);
Now, when I want to print the array, valgrind raise a "invalid read of size 4"
for (int i = 0; i < t; i++) {
printf("%d -- ", *suff[i]);
}
My question is, what I did wrong in order to access to the int value of the array?
Note : I can't change the int **suff
The problem is *suff[i]. The way operator precedence works, that does suff[i] first and then dereferences whatever it finds there. You want to do it the other way round, so add brackets:
for (int i = 0; i < t; i++) {
printf("%d -- ", (*suff)[i]);
}
This question already has an answer here:
Definitive List of Common Reasons for Segmentation Faults
(1 answer)
Closed 5 years ago.
My program need to have a function in which it finds the largest element of an array. It then returns the position of largest element. However, when finding the largest element, I am only allowed to use pointer arithmetic.
#include <stdio.h>
int *largest(int *array, int size){
int *p1 = array;
int *count, max = *p1;
for(*count = 0; count < p1 + size - 1; p1++){
if (max < *p1){
max = *p1;
count++;
}
}
return count;
}
int main(void){
int *array, size = 10;
printf("enter elements; ");
for(int i = 0; i < size; i++){
scanf("%d ", &array);
array++;
}
printf("\nThe largest element in the array is in element %d", *largest(array, size));
}
However, when I run the program, after enter values for the elements, it gives me:
segmentation fault (core dumped)
Mistakes in the function main:
You didn't allocate memory for the array. You need to add line array = (int*) malloc(sizeof(int) * size);. Without this line you get segmentation fault.
Another mistake is in filling array. Array is pointer already so you don't have to reference it again. Now you are changing pointer, not array values
Potential bug: In loop when you fill array, you increase pointer, so you loose information about beginning of array. You can get it again after loop doing array = array - size;, but it won't work if you break loop earlier. It is better to work with temporary pointer.
Mistakes in the function largest:
You created pointer count, which is not allocated and then in for loop initialization you write value 0 to unknown address. Causes segmentation fault.
In for loop you are trying to read memory from address 0 to address array + size - 2, but you want to read it from beginning of array to the end of array which is from array to array + size - 1.
Returning count makes no sense, but to sum it up, look at the example.
Pointer is just number which is address to memory, so when you don't allocate it or don't assign existing pointer, then it points randomly to memory and OS don't let you access that memory. It can happen that you will read something from random pointer, but new compilers sets initial value to 0. In BSD you can read from address 0, but linux cause segmentation fault (I hope that I didn't switch it). Writing to address 0 causes segmentation fault in both systems.
You should also check in function if you got valid pointer and allocation can fail so you need to check pointer immediatelly after allocation too. To sum this: Never trust pointer, always check it's validity.
Example doesn't check validity of pointers.
#include <stdio.h>
int *largest(int *array, int size){
int *end = array + size; // address behind array
int *max = *array; // address with largest value
for(; array < end; ++array){ // you dont need initialization since the array points to beginning
if (*max < *array){ // compare values, not address
max = array; // save position of pointer with largest value
}
}
return max; // return address with largest value
}
int main(void){
int *array, size = 10;
array = (int*)malloc(sizeof(int) * size); // allocate memory
printf("enter elements; ");
int *tmp = array; // temporary variable to not loose information about beginning of array
for(int i = 0; i < size; i++){
scanf("%d ", tmp); // reference is not needed since tmp is already pointer to value
tmp++;
}
printf("\nThe largest element in the array is in element %d", *largest(array, size));
}
I have a random number generator feeding numbers into an array, but when I print out the table, the last line is always a set of values out of the boundaries that I defined in the following function:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int temp[22];
int n;
for(n=0; n<23; n++){
temp[n] = rand()%(100 + 1 - 60) + 60;
printf("%d , %d \n", n, temp[n]);
}
return 0;
Ive created something of this nature before, but now its acting up, I just dont know where.
You are accessing the array outside the bounds which is undefined behaviour.
Instead make use of sizeof operator to avoid such problems:
for(n = 0; n < sizeof temp/sizeof temp[0]; n++)
But note that if temp were to be an malloc'ed pointer (int *temp = malloc(23 * sizeof *temp);) then sizeof wouldn't work.
Your array is being accessed outside of its bounds.
int temp[22];
This declaration assigns 22 indices to temp, temp[0] is the first
value and temp[21] is the last value you can access in your array. Counting 0, from 0..21 = we have 22 values
Your for loop is incorrect:
for(n=0; n<23; n++)
This will make the program attempt to access temp[22], which doesn't exist. You need to change it to:
for(n=0; n<22; n++)
Furthermore:
return 0; needs to be inside and at the end of your main() function. It's possibly a typo, but you're missing a closing brace } in your main() function, at least how you posted it.
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++?
In this piece of code, I am trying to have the user input an int value (x), and then have this value compared in the while loop below: while(k < x). My program crashes when I do this.
int main()
{
long int sum = 0;
long int i = 1;
long int j = 2;
long int k = 0;
int x = 0;
printf("This program will sum up all of the evenly valued terms from the
Fibionacci sequence, up until the\n user-specified highest term value.\n");
printf("Set this limit: ");
scanf("%d",x);
while(k < x)
{
k = i + j;
if(k%2==0)
sum +=k;
i = j;
j = k;
}
printf("The sum of all of the evenly valued terms of the Fibionacci sequence up until the value %d is %d",x,sum);
return 0;
}
Your program crashes because of this line:
scanf("%d",x);
C passes arguments by value, not by reference. Consequently, for a C function to be able to modify a variable from the caller, the function expects a pointer, and the caller must pass the variable's address:
scanf("%d", &x);
By neglecting to pass the address, scanf attempts to write to some arbitrary location in memory (in this case, address 0), which results in undefined behavior.
Also see Q12.12 from the comp.lang.c FAQ.
Here you need an address:
scanf("%d",x); // ==> scanf("%d", &x);
otherwise strange things can happen. In C, when you are expecting to receive result in a function parameter you pass an address.