Valgrind Invalid read of size 4 segfault - c

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]);
}

Related

How do i use a pointer in C to return a value?

I am trying to make a pointer P return to me the index of the first occurrence of given number in an array using count function that i wrote (J's job is to return the number of occurrences), the idea here is that im trying to write a function that returns 2 values instead of 1 (P returns index of first occurrence and J returns its number) in such way:
int count(int h[],int *p,int size,int d)
{
int j=0;
int bool = 0;
for(int i=0; i<size ;i++)
{
if(h[i]==d && bool == 0)
{
j++;
bool = 1;
p = &i;
}
else if(h[i]==d)
j++;
}
if(bool==0)
{
j=-1;
*p=-1;
return j;
}
else
return j;
}
void main ()
{
int j;
int *p = NULL;
int h[] = {1,2,3,4,5,1,1,3,4};
j = count(h, p , sizeof(h)/sizeof(int) , 1);
printf("%d %d", *p,j);
}
I am fully aware aware that instead of using int *p, i can simply use P and pass its address in such way:
void printarray(int h[],int size){
for(int i=0;i < size ;i++)
{
printf(" %d ",h[i]);
}
printf("\n");
}
int count(int h[],int *p,int size,int d)
{
int j=0;
int bool = 0;
for(int i=0; i<size ;i++)
{
if(h[i]==d && bool == 0)
{
j++;
bool = 1;
*p = i;
}
else if(h[i]==d)
j++;
}
if(bool==0)
{
j=-1;
*p=-1;
return j;
}
else
return j;
}
void main ()
{
int j;
int p;
int h[] = {1,2,3,4,5,1,1,3,4};
printarray(h,sizeof(h)/sizeof(int));
j = count(h, &p , sizeof(h)/sizeof(int) , 1);
printf("%d %d", p,j);
}
What Really intrigues me is that why does it show a segmentation fault when using the pointer ? or am i just wrong about using a pointer in the first place and i should pass the address of an int in case i want my function to return 2 values for me ?
That which is a pointer has to point to something. So when you wrote int *p = NULL; you didn't give it somewhere to point. You could have done int n; int *p = &n; and proceed to pass p.
But it gets bumpy from here. You tried to write p = &i; inside the function. While that's completely valid code, from that point, assigning to *p will mess up your loop control function. This is not what you want. In the "I know I can" section you have the more reasonable *p = i;.
I'm guessing you want to know how to pass something allocated in the function to its caller. You can in fact do this; there's standard library functions designed for this task. You can in fact write
int count(int h[],int **p,int size,int d)
{
int j=0;
int bool = 0;
for(int i=0; i<size ;i++)
{
if(h[i]==d && bool == 0)
{
j++;
bool = 1;
*p = malloc(sizeof(int));
**p = i;
}
else if(h[i]==d)
j++;
}
if(bool==0)
{
j=-1;
return j;
}
else
return j;
}
void main ()
{
int j;
int *p = NULL;
int h[] = {1,2,3,4,5,1,1,3,4};
j = count(h, &p , sizeof(h)/sizeof(int) , 1);
if (p) {
printf("%d %d", *p,j);
free(p);
} else {
printf("(no index) %d", j);
}
}
So what happened here is we have a pointer in main() that is initialized to point nowhere, may or may not be set in count to point to the index. If nothing is found, p will still point to NULL (nowhere). The function malloc() returns the newly allocated memory so that p has somewhere to point; and the function free returns it.
** is a simple idea that gives people headaches. Since a pointer is * we add another * when we want a pointer to a pointer, so we can change that pointer. Just don't ask how deep you can go. The answer is don't try. Two happens a lot; three requires a good justification, and more than three is almost never done. More than two really is a headache and nobody wants headaches on their headaches. The limit is way higher. Nobody goes there.
It probably seems rather pointless, and it is. malloc() is used to allocate entire arrays in the function (whose size isn't known until runtime) and return them to the caller. A single int just isn't worth managing like this (the pointer is bigger than it is), but for an array it makes sense. So much that in big programs, almost everything is on the heap; unlike the small programs everybody starts with where almost everything is on the stack (local variables are on the stack).
You thinking about what you want to do correctly, but you are over complicating how to do it a bit. Instead of all the if ... else ... statements, what if you just used a flag like what you call bool (but let's rename it to something that won't conflict with the type from stdbool.h), call it first_set instead. Initialize it with a value of 0 (false) to begin with, and then when you find the first occurrence, update first_set = 1;
If you step back and thing of what your primary check needs to be, all you are really worried about locating in your array is the first, and all remaining indexes where the given value (let's call val instead of d) is equal to the array element. (and since a count, a length and an array index cannot be negative, let's choose size_t as the type for the positive counting values). To track the number of occurrences, let's use occurs as the variable (helps keep things readable in long programs)
So all you really want to do is loop over each element in your array and check if the current element is equal to the value you are searching for. That is the primary concern from which all other actions can be taken. You can keep your parameters in the order you like, but I find it easier to think about the function (1) taking an array, (2) of a given number of elements, where I will find (3) the first occurrence or (4) a given value. (whatever makes sense to you, but is also readable to whoever works on your code later) So with a slight tweak of the ordering (at least for my old eyes), you could set up your function to loop over each element and locate all of the occurrences of a given value as:
size_t arr_occurrences (int *a, size_t nelem, size_t *first, int val)
{
int first_set = 0; /* flag if 1st occurrence set */
size_t occurs = 0; /* total no. of occurrences */
for (size_t i = 0; i < nelem; i++) { /* loop over each element */
if (a[i] == val) { /* is it equal to val? */
...
occurs += 1; /* increment no. of occurrences */
}
}
return occurs; /* return total number of occurrences */
}
The only thing left to add is how to set the first occurrence. While you talk in terms of locating the "address" of the first occurrences in the function, what I think you really mean is locating the "index" of the first occurrence within the array. You can convert the index back to an address in the calling function and not have to worry about passing something that can hold the address (which would require passing a pointer-to-pointer rather than a pointer-to int)
So the first time the test of a[i] == val tests true, you want to capture the index and save it, ensuring you don't change it for any of the other times a[i] == val tests true during your loop. You have your first_set flag that is currently set to 0 (false), so all you really need to capture your first index in the array where val occurs is:
if (!first_set) { /* if first not set */
*first = i; /* update value at address of first */
first_set = 1; /* set first_set flag true */
}
If you put that in place of the ... placeholder in the function above, you would have:
size_t arr_occurrences (int *a, size_t nelem, size_t *first, int val)
{
int first_set = 0; /* flag if 1st occurrence set */
size_t occurs = 0; /* total no. of occurrences */
for (size_t i = 0; i < nelem; i++) { /* loop over each element */
if (a[i] == val) { /* is it equal to val? */
if (!first_set) { /* if first not set */
*first = i; /* update value at address of first */
first_set = 1; /* set first_set flag true */
}
occurs += 1; /* increment no. of occurrences */
}
}
return occurs; /* return total number of occurrences */
}
Short and sweet, no else needed, just a check of your flag first_set and if it isn't set, capture the index and set first_set true so you don't change in during the remainder of your loop. Your function makes the index of the first occurrence of val available back in the calling function by updating the value at the address held by the pointer first. The function returns the total number of occurrences for val in your array so it too is available to the caller. (with a slight change of type to size_t)
(another benefit of using size_t on platforms where size_t is larger than int is your array (or allocated block) can hold more than INT_MAX values and your code will still work without risk of integer overflow if a count exceeds what can be represented by an int)
Putting it altogether in a short example that creates an array of 100 elements holding random values from -10 to 10 and then chooses the value to find by choosing a random value in that range, you could check that all works as expected as follows:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define NELEM 100 /* if you need a constant, #define one (or more) */
#define PERROW 10
#define LO_LIM -10
#define HI_LIM 10
int rand_in_range (int lowlim, int highlim)
{
return rand() % (highlim - lowlim + 1) + lowlim;
}
void arr_fill_rand (int *a, size_t nelem, int lowlim, int highlim)
{
for (size_t i = 0; i < nelem; i++)
a[i] = rand_in_range (lowlim, highlim);
}
void arr_prn (int *a, size_t nelem, const char* fmt)
{
const char *format = fmt != NULL ? fmt : " %d";
for (size_t i = 0; i < nelem; i++) {
if (i && i % PERROW == 0)
putchar ('\n');
printf (format, a[i]);
}
putchar ('\n');
}
size_t arr_occurrences (int *a, size_t nelem, size_t *first, int val)
{
int first_set = 0; /* flag if 1st occurrence set */
size_t occurs = 0; /* total no. of occurrences */
for (size_t i = 0; i < nelem; i++) { /* loop over each element */
if (a[i] == val) { /* is it equal to val? */
if (!first_set) { /* if first not set */
*first = i; /* update value at address of first */
first_set = 1; /* set first_set flag true */
}
occurs += 1; /* increment no. of occurrences */
}
}
return occurs; /* return total number of occurrences */
}
int main (void) {
int arr[NELEM] = {0}, /* array of NELEM set all zero */
val = 0; /* value to find */
size_t first = 0, /* index of first occurrence */
occurs = 0; /* total no. of occurrences */
srand (time(NULL)); /* seed random number generator */
val = rand_in_range (LO_LIM, HI_LIM); /* random in LO to HI (inclusive) */
arr_fill_rand (arr, NELEM, LO_LIM, HI_LIM); /* fill with random values in range */
arr_prn (arr, NELEM, " % 3d");
occurs = arr_occurrences (arr, NELEM, &first, val); /* get occurrences of val */
printf ("\n%d occurs first in array of %d " /* output results */
"elements ranging from %d to %d at:\n"
" index : %zu\n"
" address : %p\n"
"and occurs a total of %zu times.\n",
val, NELEM, LO_LIM, HI_LIM,
first, (void*)&arr[first], occurs);
}
(note: you never need more than one call to printf() (or fputs() or puts()) to provide on block of output, regardless of the number of lines it contains. You can keep things readable in longer output by breaking the string up into adjacent strings (newlines and other whitespace between them is ignored) and the compiler with create a single string to output from all adjacent string literals)
Example Use/Output
The program outputs the array and then outputs the results with the index of the first occurrence (and it's actual address if that is what you wanted) along with the total number of times the value of interest was found:
$ ./bin/arr_rand_1st_occ+count
3 -10 2 10 2 -9 4 5 -3 7
-4 -6 10 -4 8 -5 8 5 -10 10
10 6 -3 2 -5 1 1 8 10 -1
6 0 -1 -5 -1 10 -6 -10 4 1
5 -10 6 5 -4 1 8 -8 -4 8
-9 -7 2 -4 5 7 5 -7 3 4
2 -4 -6 10 1 1 9 5 0 0
-7 -6 -2 9 7 3 -2 4 3 4
2 4 5 -9 8 -3 6 2 0 -2
-6 -10 4 -2 8 -8 7 6 5 -4
8 occurs first in array of 100 elements ranging from -10 to 10 at:
index : 14
address : 0x7ffea2fb5938
and occurs a total of 7 times.
The array is output with 10 values PERROW to make things easier to read. Remember when confirming the results, arrays are zero-indexed in C.
Last note is unless you are programming in a freestanding environment (without the benefit of any OS), the allowable declarations for main for are int main (void) and int main (int argc, char *argv[]) (which you will see written with the equivalent char **argv). See: C11 Standard - §5.1.2.2.1 Program startup(p1). See also: What should main() return in C and C++?
In a freestanding environment (such as programming on a microcontroller) without the benefit of an operating-system, the name and type of the function called at program startup are implementation-defined. See: C11 Standard - 5.1.2.1 Freestanding environment
Look things over and let me know if you have further questions.
Your program behaviour is undefined because it end up dereferencing a NULL pointer here:
int *p = NULL;
int h[] = {1,2,3,4,5,1,1,3,4};
j = count(h, p , sizeof(h)/sizeof(int) , 1);
printf("%d %d", *p,j);
^^
|
Dereferencing p which is a NULL pointer
The way you are passing the p pointer from main() function to count() function, you are passing NULL. That means, in context of your program, this
j = count(h, p , sizeof(h)/sizeof(int) , 1);
is equivalent to this
j = count(h, NULL , sizeof(h)/sizeof(int) , 1);
The count() function parameter p will receive NULL as argument i.e. it's equivalent to p = NULL (where p is count() function parameter).
Whatever you assign to p in count() function, you are actually modifying a local variable of count() function. No changes are going to reflect in pointer variable p of main() function and it will remain a NULL pointer.
Now, lets come to the count() function.
In this snip of code of count() function:
for(int i=0; i<size ;i++)
{
if(h[i]==d && bool == 0)
{
j++;
bool = 1;
p = &i;
}
else if(h[i]==d)
j++;
}
the scope and life of loop variable i is within the for loop block. Once, the loop exit the lifetime of i is ended. JFYI - accessing an object outside of its lifetime is undefined behaviour. So, if p hold &i and out of loop body if your program access p then it will lead to undefined behaviour. Also, *p=-1; statement in count() will also lead to undefined behaviour because, in count() function p will be a NULL pointer if bool==0.
Remember, if a function is passing a pointer to another function as a argument and expecting that function to modify the value of pointer, which it receive as parameter, then the pointer should be pointing to a valid memory location before the calling function access and modify it's memory contents or the caller function should pass address of pointer as argument and let the calling function allocate memory dynamically to it so that it should be accessible from the caller function as well (which is main() function, in your case).
There are couple ways to achieve this.
Method I:
Pass a valid memory location to calling function.
Either pass address of a local variable of caller function as argument (this is same as your second code snippet)
int main (void) {
int j;
size_t res = 0;
size_t *p = &res; // p is pointing to res variable
int h[] = {1, 2, 3, 4, 5, 1, 1, 3, 4};
int num = 1;
j = count (h, p, sizeof (h) / sizeof (int), num);
if (j != -1) {
printf ("%zu %d", *p, j);
} else {
printf ("%d not found\n", num);
}
return 0;
}
Or allocate memory to pointer in caller function and pass it
int main (void)
{
int j;
size_t *p = NULL;
int h[] = {1, 2, 3, 4, 5, 1, 1, 3, 4};
int num = 1;
p = malloc (sizeof (size_t));
if (p == NULL) {
fprintf (stderr, "Failed to allocate memory");
exit (EXIT_FAILURE); // or whatever you want to do in case of allocation failure
}
j = count (h, p, sizeof (h) / sizeof (int), num);
if (j != -1) {
printf ("%zu %d", *p, j);
} else {
printf ("%d not found\n", num);
}
free(p);
return 0;
}
and the count() function implementation for both the above cases:
int count (int h[], size_t *p, size_t size, int d) {
int j = 0;
for (size_t i = 0; i < size ; ++i) {
if(h[i] == d) {
if (j == 0) {
*p = i;
}
++j;
}
}
return j == 0 ? -1 : j;
}
Method II:
Pass the address of p and dynamically allocate memory to p in count() function before accessing it. Note that, objects with allocated storage duration live until they are destroyed by a call to free(). So, if count() function allocates memory to a pointer, whose address passed as argument to count() function from main() function, then that memory will be accessible in main() function as well via pointer variable p.
#include <stdio.h>
#include <stdlib.h>
int count (int h[], size_t **p, size_t size, int d) {
int j = 0;
for(size_t i = 0; i < size ; ++i) {
if(h[i] == d) {
if ((j == 0) && (p != NULL)) {
*p = malloc (sizeof (size_t));
if (p == NULL) {
fprintf (stderr, "Failed to allocate memory");
exit (EXIT_FAILURE);
}
**p = i;
}
++j;
}
}
return j == 0 ? -1 : j;
}
int main (void) {
int retval;
size_t *p = NULL;
int h[] = {1, 2, 3, 4, 5, 1, 1, 3, 4};
int num = 3;
retval = count (h, &p, sizeof (h) / sizeof (int), num);
if (retval != -1) {
printf ("%zu %d\n", *p, retval);
} else {
printf ("%d not found\n", num);
}
// free memory once you are done with it
if (p != NULL) {
free (p);
}
return 0;
}
Additional:
Using void as return type of main function is not as per standards. The return type of main function should be int.
You are trying to return pointer pointing to a place which will be no longer valid once the loop completed it's execution, either declare i outside for or don't use the pointer part, as dereferencing a null pointer is illegal, also, you get segmentation fault when you try to access memory you have no business with and no permission to read or write, in this case, pointing to a memory location which is out of scope.
Instead of returning a pointer,simply create a local array of same type in the function, first index for first occurence of the given number, and second index for the total occurence, and return the array but make sure the return type should be pointer of same type.
edit: thanks Mr. Joshua, for pointing out the mistake.

How to use pointer to bidimensional array C

How do I edit a value in an array with pointer in C?
int *pointer;
int array[3][1];
I tried this:
int *Pointer
int array[2][2];
Pointer[1][1]= 6;
but when compiling, I get a segmentation fault error. What to do?
Given some array int Array[Rows][Columns], to make a pointer to a specific element Array[r][c] in it, define int *Pointer = &Array[r][c];.
Then you may access that element using *Pointer in an expression, including assigning to *Pointer to assign values to that element. You may also refer to the element as Pointer[0], and you may refer to other elements in the same row as Pointer[y], where y is such that 0 ≤ y+c < Columns, i.e., Pointer[y] remains in the same row of the array.
You may also use Pointer[y] to refer to elements of the array in other rows as long as none of the language lawyers see you doing it. (In other words, this behavior is technically not defined by the C standard, but many compilers allow it.) E.g., after Pointer = &Array[r][c];, Pointer[2*Columns+3] will refer to the element Array[r+2][c+3].
To make a pointer you can use to access elements of the array using two dimensions, define int (*Pointer)[Columns] = &Array[r];.
Then Pointer[x][y] will refer to element Array[r+x][y]. In particularly, after int (*Pointer)[Columns] = &Array[0]; or int (*Pointer)[Columns] = Array;, Pointer[x][y] and Array[x][y] will refer to the same element.
You can access any given element with this syntax: array[x][y].
By the same token, you can assign your pointer to any element with this syntax: p = &array[x][y].
In C, you can often treat arrays and pointers as "equivalent". Here is a good explanation:
https://eli.thegreenplace.net/2009/10/21/are-pointers-and-arrays-equivalent-in-c
However, you cannot treat a simple pointer as a 2-d array. Here's a code example:
/*
* Sample output:
*
* array=0x7ffc463d0860
* 1 2 3
* 4 5 6
* 7 8 9
* p=0x7ffc463d0860
* 0x7ffc463d0864:1 0x7ffc463d0868:2 0x7ffc463d086c:3
* 0x7ffc463d0870:4 0x7ffc463d0874:5 0x7ffc463d0878:6
* 0x7ffc463d087c:7 0x7ffc463d0880:8 0x7ffc463d0884:9
*/
#include <stdio.h>
int main()
{
int i, j, *p;
int array[3][3] = {
{1,2,3},
{4,5,6},
{7,8,9}
};
// Dereference 2-D array using indexes
printf("array=%p\n", array);
for (i=0; i < 3; i++) {
for (j=0; j < 3; j++)
printf ("%d ", array[i][j]);
printf ("\n");
}
// Dereference 2-D array using pointer
p = &array[0][0];
printf("p=%p\n", p);
for (i=0; i < 3; i++) {
for (j=0; j < 3; j++)
printf ("%p:%d ", p, *p++);
printf ("\n");
}
/* Compile error: subscripted value p[0][0] is neither array nor pointer nor vector
p = &array[0][0];
printf("p=%p, p[0]=%p, p[0][0]=%p\n", p, &p[0], &p[0][0]);
*/
return 0;
}
Cast the 2D-array into 1D-array to pass it to a pointer,
And then, You are ready to access array with pointer. You can use this method to pass 2D-array to a function too.
#include <stdio.h>
int main()
{
int arr[2][2];
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
arr[i][j] = (2 * i) + j;
}
}
int *Pointer = (int *)arr; // Type conversion
/*
&arr[0][0] = Pointer + 0
&arr[0][1] = Pointer + 1
&arr[1][2] = Pointer + 2
&arr[2][2] = Pointer + 3
Dereference Pointer to access variable behind the address
*(Pointer + 0) = arr[0][0]
*(Pointer + 1) = arr[0][1]
*(Pointer + 2) = arr[1][2]
*(Pointer + 3) = arr[2][2]
*/
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
printf("%d ", *(Pointer + (2 * i) + j)); // Accessing array with pointer
}
printf("\n");
}
return 0;
}
Using the function wv_matalloc from https://www.ratrabbit.nl/ratrabbit/content/sw/matalloc/introduction , you can write the following code:
#include <stdio.h>
#include "wv_matalloc.h"
int main()
{
double **matrix;
int m = 3;
int n = 4;
// allocate m*n matrix:
matrix = wv_matalloc(sizeof(double),0,2,m,n);
// example of usage:
int i,j;
for (i=0; i<m; i++)
for (j=0; j<n; j++)
matrix[i][j] = i*j;
printf("2 3: %f\n",matrix[2][3]);
}
Compile with:
cc -o main main.c wv_matalloc.c
1.
You never assigned a value to Pointer in your example. Thus, attempting to access array by Pointer invokes undefined behavior.
You need to assign Pointer by the address of the first element of array if the pointer shall be a reference:
Pointer = *array;
2.
You can't use 2D notation (p[1][1]) for a pointer to int. This is a C syntax violation.
3.
Since rows of static 2D arrays are allocated subsequent in memory, you also can count the number of array elements until the specific element of desire. You need to subtract the count by 1 since indexing start at 0, not 1.
How does it work?
Each row of array contains 2 elements. a[1][1] (the first element of the second row) is directly stored after the first two.
Note: This is not the best approach. But worth a note beside all other answers as possible solution.
#include <stdio.h>
int main (void)
{
int *Pointer;
static int array[2][2];
Pointer = *array;
Pointer[2] = 6;
printf("array[1][1] (by pointer) = %d\n", Pointer[3]);
printf("array[1][1] (by array istelf) = %d\n", array[1][1]);
}
Output:
array[2][2] (by pointer) = 6
array[2][2] (by array istelf) = 6
Side Notes:
To address the first element of the second row by array[1][2] invokes undefined behavior. You should not use this way.
"but when compiling, I get a segmentation fault error."
Segmentation fault error do not occur at compile time. They occur at run time. It just gives you the impression because high probably your implementation immediately executes the program after compilation.

Understanding why it does not find duplicates in array

I wrote the following function in C:
int last(long arr[], int length) {
for (int i = 0; i < length-1; i++)
if (*(arr+i) == *(arr + length - 1))
return 1;
return 0;
}
it checks if the last value of the array was used more than once. In the main:
int *arr = malloc(length*sizeof(int));
for (int i = 0; i < length; i++)
scanf("%d", ++arr);
printf(last((long *) arr, length);
For some reason for the array [1,2,2,3] it returns that the last element was used multiple times and I'm not sure why. I think that is because of scanf("%d", ++arr); but I don't know how to fix it.
My goal is that it will return 1 for [1,3,2,3] and 0 for [1,2,2,3]. What could be the problem?
You should use scanf("%d", &arr[i]);. Using ++arr causes the array to be incremented before you pass it to last, and also reads into data beyond arr, which is undefined behavior.
Another one of the issues in this is the cast to long *.
You should use %ld in scanf and long *arr = malloc(length*sizeof(*arr));.
Also make sure to check for NULL. You never know when malloc is going to fail or someone's going to pass bad data.
Full example:
#include <stdio.h>
#include <stdlib.h>
int last(long arr[], int length) {
if(!arr) return -1;
for (int i = 0; i < length-1; i++)
{
if (arr[i] == arr[length-1])
return 1;
}
return 0;
}
int main(void)
{
long *arr = malloc(4*sizeof(*arr));
if(!arr) return 1;
for (int i = 0; i < 4; i++)
scanf("%ld", &arr[i]);
printf("%d\n", last(arr, 4));
}
Several problems in your code:
Look at this statement:
scanf("%d", ++arr);
^^^^^
In the last iteration of loop, the pointer arr will be pointing to one element past end of array arr (due to pre-increment) and it is is passed to scanf(). The scanf() will access the memory location pointed by the pointer which is an invalid memory because your program does not own it. This is undefined behavior. Note that a pointer may point to one element past the end of array, this is as per standard but dereferencing such pointer will lead to undefined behavior.
Once the main() function for loop finishes the arr pointer pointing to location past the end of memory allocated to arr and just after this you are passing arr to last() function. So, you are passing an invalid memory reference to last() function and then accessing that memory in last() function - one more undefined behavior in your program.
Probably you should take another pointer and point it to arr, so that arr keep pointing to allcoated memory reference returned by malloc().
Note that if you want to read the input the way you are doing then use the post-increment operator in scanf(), like this:
int *arr = malloc(length*sizeof(int));
if (arr == NULL)
exit(EXIT_FAILURE);
int *ptr = arr;
for (int i = 0; i < length; i++)
scanf("%d", ptr++);
but the more appropriate and readable way is - scanf("%d", &arr[i]).
Another big problem in your code is accessing the int values as long type.
The last() function parameter arr type is long and you are passing it int pointer typecasted to long *.
Note that the size of long and int may be different based on the platform. You cannot assume them to be of same size on all platforms.
Assume the case where int size is 4 bytes and long size is 8 bytes.
In this case, when accessing an int pointer using long type pointer then every object will be considered as 8 byte long and when you do arr+1 in last(), the pointer will be advance by 8 bytes and you will never get correct result.
Compiler must be throwing warning message on this statement:
printf(last((long *) arr, length);
because the printf() expects first argument as const char * and you are passing it int (return type of last()). You should give the first argument to printf() a string which contains appropriate format specifier('s).
Putting these altogether:
#include <stdio.h>
#include <stdlib.h>
int last(int arr[], int length) {
if (arr == NULL) {
return 1;
}
for (int i = 0; i < length - 1; i++) {
if (arr[i] == arr[length - 1]) {
return 1;
}
}
return 0;
}
int main(void) {
int length = 4;
int *arr = malloc (length * sizeof (*arr));
if (arr == NULL) {
exit(EXIT_FAILURE);
}
printf ("Enter %d numbers:\n", length);
for (int i = 0; i < length; i++) {
scanf ("%d", &arr[i]);
}
printf ("Duplicate found: %s\n", last (arr, length) == 1 ? "Yes" : "No");
return 0;
}

sprintf Producing segmentation fault

I am getting a segmentation fault from the below program.
#include <stdio.h>
#include <string.h>
void removeProcess(int*, int);
void removeProcessN(char**, int, int);
void main() {
int numPro = 0, quanTime = 0, contTime = 0, i, elemNum, time = 0;
//Supply variables with user input
printf("Enter number of processes: ");
scanf("%d", &numPro);
printf("Enter context switch time: ");
scanf("%d", &contTime);
printf("Enter quantum of time: ");
scanf("%d", &quanTime);
//Create array of number of process time
int proTime[numPro];
//Create string array for better output
char *proNames[numPro];
//Retrieves process time from user
for (i = 0; i < numPro; i++){
printf("Enter execution time for process %d: ", i);
scanf("%d", proTime + i);
sprintf(proNames[i], "p%d", i);
}
elemNum = 0;
//While a process remains active
while (numPro != 0) {
//Retrieves the element being worked with
elemNum = elemNum % numPro;
//Describe process working with
printf("Executing process %s\nStart time = %d\n", proNames[elemNum], time);
proTime[elemNum] -= quanTime;
//If process time complete, remove process
if (proTime[elemNum] <= 0){
removeProcess(proTime, elemNum);
removeProcessN(proNames, elemNum, numPro);
--numPro;
}
//Add amount of time with context time
time = time + quanTime + contTime;
elemNum++;
}
}
/**
*#param *array pointer to an array of integers
*#param elem int of the element to remove
* Removes an element 'elem' from the supplied integer array.
*/
void removeProcessN(char **array, int numElem, int elem) {
char *temparray[numElem - 1];
//Copy array to temparray except for elem to remove
int i;
for (i = 0; i < elem; i++) {
if (i == numElem) {
continue;
} else {
temparray[i] = array[i];
}
}
//End by setting the pointer of array to the temparray
array = temparray;
}
/**
*#param *array pointer to an array of integers
*#param elem int of the element to remove
* Removes an element 'elem' from the supplied integer array.
*/
void removeProcess(int *array, int elem) {
//Number of elements in the array
int numElem = sizeof(array) / sizeof(int);
int temparray[numElem - 1];
//Copy array to temparray except for elem to remove
int i;
for (i = 0; i < numElem; i++) {
if (i == elem) {
continue;
} else {
temparray[i] = array[i];
}
}
//End by setting the pointer of array to the temparray
array = temparray;
}
I know the segmentation fault is coming from sprintf. I am trying to simulate how an operating system would complete a process using round robin. I have tried using sprintf because that's what tutorials were saying online to use when trying to manipulate strings. The removeProcessN is just removing an index from the array proNames. I am mostly just concerned with the sprintf.
I have tried malloc when I do the sprintf but it would not even compile at that point. If someone could offer an explanation I'd be appreciative.
The problem here is that proNames is an array of pointers, but they are
uninitialized, so passing it to sprintf to write something, will crash. You
would have either use a double array or allocate memory with malloc. But as
you are only printing integers and the string representatuion of integers has a
maximal length, allocating memory with malloc will be more harder, because you
have to check that malloc doesn't return NULL, you have to free the memory
later, etc.
So I'd do:
char proNames[numPro][30]; // 28 characters for an int (usually 4 bytes long)
// should be more than enough
//Retrieves process time from user
for (i = 0; i < numPro; i++){
printf("Enter execution time for process %d: ", i);
scanf("%d", proTime + i);
sprintf(proNames[i], "p%d", i);
}
Your removeProcessN would need to change as well:
void removeProcessN(int numElem, int elem, int dim, char (*array)[dim]) {
for(int i = elem; i < numElem - 1; ++i)
strcpy(array[i], array[i+1]);
array[numElem - 1][0] = 0; // setting last element to empty string
}
Note that I moved the array argument at the last position, otherwise numElem
is not known and the compiler would return an error.
And now you can call it like this:
removeProcessN(elemNum, numPro, 30, proNames);
The 30 comes from the char proNames[numProp][30]; declaration.
I'd like to comment on the last line of your function removeProcessN:
//End by setting the pointer of array to the temparray
array = temparray;
That is not correct, first because temparray is local variable and ceases to
exist when the function returns. And array is local variable in the function,
so changing it doesn't affect anybody.
The alternative with memory allocation would look like this:
char *proNames[numPro];
//Retrieves process time from user
for (i = 0; i < numPro; i++){
printf("Enter execution time for process %d: ", i);
scanf("%d", proTime + i);
int len = snprintf(NULL, 0, "p%d", i);
proNames[i] = malloc(len + 1);
if(proNames[i] == NULL)
{
// error handling, free the previously allocated
// memory, and return/exit
}
sprintf(proNames[i], "p%d", i);
}
and removeProcessN:
void removeProcessN(char **array, int numElem, int elem) {
char *to_remove = array[elem];
for(int i = elem; i < numElem - 1; ++i)
array[i] = array[i+1];
free(to_remove);
array[numElem - 1] = NULL; // setting last element to NULL
// makes freeing easier as
// free(NULL) is allowed
}
And the way you originally called the removeProcessN would be OK.
If you eventually call removeProcessN for all processes, then all the memory
should be freed because removeProcessN frees it. If there are some elements
that remain in the array, then you have to free them later.
OP posted in the comments
My theory was that temparray would be a pointer to an array so I could just remove an index from the main array.
So when I say array = temparray, the pointer for array points to temparray. I know it worked for removeProcess. Is it different for strings?
The array = temparray also has no effect in removeProcess, array is still
a local variable and changing where it points to has no effect at all, because
you are changing a local variable only.
Besides the code is wrong:
int numElem = sizeof(array) / sizeof(int);
this only works for pure arrays, it does not work for pointers because
sizeof(array) returns you the size that a pointer of int needs to be stored.
Like the other function, you need to pass the site the array to the function.
If you say that this function worked, then just only by accident, because it
yields undefined behavior. By incorrectly calculating the number of elements,
temparray will have the wrong size, so here temparray[i] = array[i]; you may
access beyond the bounds which leads to undefined behaviour. Undefined behaviour
means that you cannot predict what is going to happen, it could be anything from
crashing to formatting your hard drive. Results that result from undefined
behaviour are useless.
And again array = temparray; just changes where the local variable array is
pointing, the caller of removeProcess doesn't see that.
The correct version would be:
int removeProcess(int *array, int elem, int numElem) {
if(array == NULL)
return 0;
// nothing to do if the elemnt to be removed is
// the last one
if(elem == numElem - 1)
return 1;
// overwriting the memory, because memory
// regions overlap, we use memmove
memmove(array + elem, array + elem + 1, numElem - elem - 1);
return 0;
}
So, to make it clear:
Let's look at this code:
void sum(int *array, size_t len);
{
int c[len];
array = c;
}
void bar(void)
{
int x[] = { 1, 3, 5 };
size_t len = sizeof x / sizeof *x;
sum(x, sizeof x / sizeof *x);
printf("x[0] = %d, x[1] = %d, x[2] = %d\n", x[0], x[1], x[2]);
}
sum has only a copy of the pointer you've passed in bar, so from bar's
point of view, sum changed the copy, so bar will print
x[0] = 1, x[1] = 3, x[2] = 5.
But if you want that the caller sees any change, then you to access through the
pointer:
void sum(int *array, size_t len)
{
int c[len];
for(size_t i = 0; i < len; ++i)
array[i] += 10;
array = c;
}
With this version bar would print x[0] = 11, x[1] = 13, x[2] = 15 and
and array = c will have no effect on bar.

Element values show incorrect when print out from an array

I am just learning C and have my program print out incorrect values but I don't know how to fix it therefore I'd like to have your help.
Here is the codes . The test function stores integer numbers (from 0 to 20) in an array and return it. That array is copied to a new array (p[20]) in the main function and I try to print every element of that array out using for loop however the value is not correct, for example i = 0 then p[0] should be 0 but it shows -443987883 ,....
#include <stdio.h>
int test();
int main ()
{
int p[20];
strcpy(p , test);
int i;
int N = 20;
for (i=0; i < N; i++) {
printf ("%i,%i\n", i , p[i]);
}
}
int test (int i , char o[])
{
int N = 20;
for (i = 0; i < N; i++) {
o[i] = i;
}
return o;
}
Your code contains a lot of errors. I am going to point them out and explain to you how to fix it.
First of all, you should definitely forget the statement :
strcpy(p , test);
as by this you try to copy a function to an array! If you think that this statement calls test function and passes p as an argument to this, this is not true.
If you want another function, other than main, to fill your array, the best way would be to dynamically allocate a pointer to int and pass it by reference to the function. You can read more about passing by reference or by value here.
Let's see how you can do this. First of all, define N as a constant value outside your program :
#define N 20
Then, your main function should be modified like this :
int main ()
{
int *p;
int i;
//Dynamically allocate a pointer to ints
p = malloc(N*sizeof(int));
if (p == NULL)
printf ("Error in allocating memory\n");
//Now call your function
p = test(&p); //pass the pointer by reference
for (i = 0; i < N; i++)
printf ("%d, %d\n", i , p[i]);
}
and finally your test function should be modified accordingly like this :
int* test (int** p)
{
for (i = 0; i < N; i++)
*p[i] = i;
return *p;
}
So the prototype of your test function should change from :
int test();
to :
int* test(int**);

Resources