Segmentation fault in C program using pointers as parameters - c

Im trying to understand pointers as function parameters, and in one of the programs there is a segmentation error I can't fix. Firstly, why to use pointers in function arguments? and Why is this error showing?
#include <stdio.h>
void square_it(int* a)
{
printf("The final value is: %d\n", *a * *a);
}
int main()
{
int* input;
puts("This program squares the input integer number");
puts("Please put the number:");
scanf("%d", &input);
square_it(input);
return 0;
}

int* input; does not allocate memory for an int. It mearly makes it possible to make input point at an int (allocated elsewhere). Currently, by dereferencing it (like you do with *a), you make your program have undefined behavior. If you really want an intermediate pointer variable for this, this example shows how it could be done:
#include <stdio.h>
void square_it(int *a) {
*a *= *a; // same as *a = *a * *a;
}
int main() {
int data;
int* input = &data; // now `input` points at an `int`
puts("This program squares the input integer number");
puts("Please put the number:");
// check that `scanf` succeeds:
if(scanf("%d", input) == 1) { // don't take its address, it's a pointer already
square_it(input);
// since `input` is pointing at `data`, it's actually the value of `data`
// that is affected by `scanf` and `square_it`, which makes the below work:
printf("The final value is: %d\n", data);
}
}
Without an intermediate pointer variable:
#include <stdio.h>
void square_it(int *a) {
*a *= *a;
}
int main() {
int input; // note that it's not a pointer here
puts("This program squares the input integer number");
puts("Please put the number:");
if(scanf("%d", &input) == 1) { // here, taking the address of `input` makes sense
square_it(&input); // and here too
printf("The final value is: %d\n", input);
}
}
Without any pointers at all, it could look like this:
#include <stdio.h>
int square_it(int a) {
return a * a;
}
int main() {
int input;
puts("This program squares the input integer number");
puts("Please put the number:");
if(scanf("%d", &input) == 1) { // here, taking the address of `input` makes sense
int result = square_it(input);
printf("The final value is: %d\n", result);
}
}

This is the working code:
#include <stdio.h>
void square_it(int* a)
{
printf("The final value is: %d\n", *a * *a);
}
int main()
{
int i = 0;
int* input = &i;
puts("This program squares the input integer number");
puts("Please put the number:");
scanf("%d", input);
square_it(input);
return 0;
}
There are some errors in the original code:
According to the man-pages to scanf, it takes a format string and then the address of where to store the input.
You gave it the address of a pointer (eg. an int**), which is not what scanf expects.
Also you need to provide memory to store the input in. The scanf string tells that you want an integer as input. In the above code snippet that is i.
input points to i, so i can give the int*, that is input to scanf. scanf will then write into i. We can then go ahead and put the address of i into the sqare_it function.
Since we did not use the heap, we don't need to worry about memory management.

Related

Unexpected value by using printf (Call by reference in C)

#include <stdio.h>
int main()
{
int num1;
int *p;
p=&num1;
printf("Give a value\n");
scanf("%d", &num1);
printf("\n%d", num1);
f2(&num1);
printf("%d", *p);
return 0;
}
void f2(int *p)
{
*p *= *p;
}
A call by reference program just to return the square of a value
Well, the problem is that if I do not use printf the expected output is correct (e.g. 2*2=4)
However, if I include:
printf("\n%d", num1);
and run the programm I will take a non expected value (e.g. 2*2=24)
These two calls of printf result of outputting two values in the same line without a space.
printf("\n%d", num1);
f2(&num1);
printf("%d", *p);
If you want to make the output less confusing then for example write
printf("\n%d", num1);
f2(&num1);
printf("\n%d\n", *p);
There are two problems in your code.
You need to declare void f2(int* p) before using it. Depending on your platform you might get away with it. But a sane compiler should give you at least a warning (which should be considered as an error).
Sloppy format strings in your printfs make the output look wrong.
Try this:
#include <stdio.h>
void f2(int* p); // you need to declare this, otherwise you'll get a
// warning you should always conside as an error
int main()
{
int num1;
int* p;
p = &num1;
printf("Give a value\n");
scanf("%d", &num1);
printf("\nnum1 = %d\n", num1); // format string more explicit
f2(&num1); // warnig here if f2 is not declared as above
printf("*p = %d\n", *p); // format string more explicit
return 0;
}
void f2(int* p)
{
*p *= *p;
}
There are several problems with this code.
You need to either:
a. declare a prototype for f2. You can do this by putting the following code before your main
void f2(int *p);
b. put the entire f2 function before main (and this is the route that I'd probably choose - but questions of style are the cause of countless pointless wars.
The output is unclear. By not putting \n in your printf statement you're running the output of the two print statements together. Use this instead:
printf("\n%d\n", num1);
Pretty printing greatly improves readability. And don't be afraid of giving functions meaningful names.
On balance, I think I'd write your code like so:
#include <stdio.h>
void square(int *p) {
*p *= *p;
}
int main(int argc, char *argv[]) {
int num1;
int *p;
p = &num1;
printf("Give a value: ");
scanf("%d", &num1);
printf("\n%d squared is equal to: ", num1);
square(&num1);
printf("%d\n", *p);
return 0;
}
#include <stdio.h>
#include <math.h>
void f2 (int *p)
{
*p = pow(*p, 2); // equal with *p *= *p;
}
int main ()
{
int num1;
int *p; // p is pointer variable that points to num1
// type of num1 and p must be the same (int).
p = &num1; // p is address of num1
printf ("Give a value: ");
scanf ("%d", p); // p is address of num1
printf ("\nnum1 before: %d", *p); // *p is num1 (content of p)
f2 (p);
printf ("\nnum1 after: %d", *p); // missing \n in here
return 0;
}

How do you pass 2-dimensional array of character into a function?

So i'm trying to pass
char parent[n][50];
into a function initialize();
And then copy the char x, into the parent [ i ] inside the initialize(); function. Example
x = "Cityname"
and when passed into the initialize();
it would do
strcpy(parent[i], x);
to make the
parent[i] = "Cityname"
void initialize(char *parent, int *ranks, char x, int i){
strcpy(parent[i], x);
ranks[i] = '0';
}
int main(){
int n, i = 1;
char x[20];
printf("Enter how many city are there : "); scanf("%d", &n); fflush(stdin);
char parent[n][20];
int ranks[n];
while(1){
printf("enter city name: "); scanf("%[^\n]", x);
if(i <= n){
initialize(parent[][20], ranks, x, i);
i++;
} else {
printf("The city is at maximum\n");
}
}
}
It tells a warning:
passing argument 1 of 'strcpy' makes pointer from integer without a cast
note: expected 'char *' but argument is of type 'char'
and also in function main
error: expected expression before ']' token
Can anyone explain how to strcpy(parent[i], x) correctly? I can't seem to figure this problem out.
I see several problems with your code. Arrays vs pointers in C can be confusing, so there are a few rules to keep in mind:
char x[n] can be automatically converted by the C compiler to char *x.
char x[10][20] is represented under the hood as a 1D array, and the compiler computes the offsets behind the scenes. For example, if x were a 10 x 20 array, the expression x[1][2] could be compiled as *(x + 22). For this reason, it can cause surprising results to cast a 2D array to a char*, and it is invalid to cast a 2D array to a char**.
With these rules in mind, here is how I would change your code
void initialize(char (*parent)[20], int *ranks, char *x, int i){
strcpy(parent[i], x);
ranks[i] = '0'; // Did you want an automatic conversion from char to int here? Maybe you meant ranks[i] = 0?
}
int main(){
int n, i = 0; // As Craig mentions, i should start at 0.
char x[20];
printf("Enter how many city are there : "); scanf("%d", &n); fflush(stdin);
char parent[n][20];
int ranks[n];
while(1){
printf("enter city name: "); scanf("%19s", x); // scanf will automatically stop at whitespace, and you must include the max length to avoid a buffer overrun.
if(i < n){
initialize(parent, ranks, x, i);
i++;
} else {
printf("The city is at maximum\n");
// Maybe break here, unless you want an infinite loop
}
}
}

How initialize array dynamically using function in C

SS4SS of 3rd Problem
I want to create the program to take the input from user until he presses 1.
I'm using dynamic memory allocation using function and after running this code, this program takes only 4 input and it does not show any output
output
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
void input(int **arr)
{
int n=1,i=0;
*arr=(int *)malloc(sizeof(int));
int ch;
do
{
printf("\nEnter '1' To Enter A Value in array or else enter '0'");
scanf("%d",&ch);
if (ch==1)
{
if (!*arr)
{
printf("\nInsufficient Memory!");
return;
}
printf("\nEnter the value\t:\t");
scanf("%d", arr[i]);
*arr=realloc(*arr,sizeof(int)*(++n));
*arr[++i]=INT_MIN;
}
else if (ch!=1&&ch!=0)
{
printf("\nInvalid input!");
continue;
}
} while(ch!=0);
free(arr);
}
void display(int **arr)
{
for (int i = 0; i < 3; i++)
printf("\n%d", **(arr+i));
free(arr);
}
int main()
{
int *arr;
input(&arr);
display(&arr);
free(arr);
return 0;
}
First question
With !*arr[i] you are checking the logical value contained in *arr[i], which can have a random value before you assign a value to it. In your case, the value contained in *arr[i] is 0, triggering the condition !*arr[i].
The correct way of checking if realoc() was succesful, is checkin it's returned value. If it's null, the request failed. In your case, it would be replacing
if(!*arr[i])
by
if(!*arr)
Second question
In this line *arr[++i]=INT_MIN; the index [] operator has precedence over pointer * operator. You have to write parenthesis:
(*arr)[++i]=INT_MIN;
And also here
scanf("%d", arr[i]);
you are saying that arr is an array, when it is a pointer to an array. You should replace it with:
scanf("%d", *arr + i);
Third question
You are also doing free() before you access the values in the array, which triggers the error. You should remove the free() calls at the end of input() and display() and leave only the one of the end of main().
You have still to replace the printf() in display with
printf("\n%d", (*arr)[i]));

Endless loop in C; for loop seems valid

I am a student trying to learn c coming from c++. I wrote the following code and it compiles fine; however, when I execute it I get an endless loop when calling the print function. I looked over the code and it seems to be valid to me, so why is it printing an endless loop?
#include <stdio.h>
#include <stdlib.h>
struct student
{
int id;
int score;
};
void generate(struct student *students, int n)
{
int randomId = rand () % n + 1;
int randomTestScore = rand() % 100 + 1;
students->id = randomId;
students->score = randomTestScore;
}
void sort(struct student *students, int n)
{
/*using insertion sort*/
for (unsigned int i = 1; i < n; ++i)
{
int next = students[i].score;
int j = i;
while(j > 0 && students[j-1].score > next)
{
students[j].score = students[j-1].score;
j--;
}
students[j].score = next;
}
}
void print(struct student *students, int n)
{
for (unsigned int i = 0; i < n; i++)
{
printf("Student at position No: %d Test Score: %d\n", i+1, students[i].score);
}
}
int main()
{
/*user enters num of students to create scores for*/
int num_students;
printf("Enter Num of students\n");
scanf("%d", num_students);
/*allocate memory for the amount of students user wants*/
struct student *userStudents = malloc(num_students*sizeof(struct student));
printf("Randomly filling students IDs & Test Scores...\n");
for (unsigned int i = 0; i < num_students; ++i)
{
generate(&userStudents[i], num_students);
}
printf("Array of students before sorting:\n");
print(userStudents, num_students);
printf("\nNow, sorting students by test scores...\n\n");
sort(userStudents, num_students);
printf("Array of students after sorting:\n");
print(userStudents, num_students);
return 0;
}
To use scanf() correctly it needs to alter the passed variable in place, and since there is no pass by refrence in c, you need to pass the address of the variable, so scanf() is able to modify it though a pointer, hence you need to use the & operator, but that is not enough.
The scanf() family of functions, return a value that must be checked before you can access the scanned values, you should never ignore that value, under any circumstances you should check for it.
What your code is doing is called undefined behavior, it's interpreting the passed integer as if it was a pointer, which is undefined behavior.
To prevent that you can activate compiler warnings, many compilers know what kind of parameter the *f functions expect, i.e. the functions which take a string as a format to be parsed and to allow the function to correctly grab the rest of the parameters passed via variable arguments to it.
The correct way to call scanf() in your program is
if (scanf("%d", &num_students) != 1)
return 1;
that is, from main() and hence it's ending the program, because you can't continue after that condition was true, in that case what actually happens is that num_students is not initialized, that would once again cause undefined behavior.
Change the call to scanf to:
/*
* correct way of calling scanf, passing the address of the wanted variable
*/
scanf("%d", &num_students);
^
This elliminates segmentation faults and makes the code runs OK on my machine.
I had a previous hint that you'd need to change your declaration of userStudents to a pointer to pointers, however I was incorrect. You are clearly correctly allocating enough contiguous memory to hold all of your structs pointed by *userStudents.

Using an Array to print out a number of asterisks, dependent on number inputted from user in C

So this program should print out the number of asterisks dependending on the number you enter, so if you enter 5, the 5 asterisks will print out.
I don't know where I am going wrong? Also if anyone can recommend a good book for C, I read through my school text and C for dummies, I am just not getting it.
void barplot(int num1, char array[]);
int main()
{
int n1;
printf("Enter a number: ");
scanf("%d",&n1);
printf("You have entered: %d\n",n1);
char astrk[n1];
strcpy(astrk, "*");
barplot(n1, astrk);
return(0);
}
void barplot(int num1, char array[])
{
printf("num1=%d\n",num1);
int i=0;
for(i=0; i<num1; i++)
{
printf("%c",array[i]);
}
}
Edit: An array is needed per the assignment
Given that you're stuck using an array, you can fill the astrk array with '*' characters using memset:
char astrk[n1];
memset(astrk, '*', n1);
barplot(n1, astrk);
return 0;
memset fills the array (the first argument) with copies of the character (the second argument), up to the length in the third argument. Note that this doesn't null-terminate the array, so you can't directly printf it.
If you do want to be able to printf it, then you should allocate enough space for the null terminator, like so:
char astrk[n1+1];
memset(astrk, '*', n1);
astrk[n1] = '\0'
printf("%s", astrk);
return 0;
Then you don't need the barplot function at all.
You don't really need a whole char array just to store one character. Let's just replace the char[] with a single char:
void barplot(int num1, char array);
int main()
{
int n1;
printf("Enter a number: ");
scanf("%d", &n1);
printf("You have entered: %d\n", n1);
barplot(n1, '*');
return 0;
}
void barplot(int num1, char ch)
{
printf("num1=%d\n",num1);
int i;
for(i=0; i<num1; i++)
{
putchar(ch);
}
}
You did not filled your astrk array with asterisks. You just copied over a string literal that has only one asterisk.
If you need only to print these asterisks, why do you need an array at all?
try this:
void barplot(int num1)
{
printf("num1=%d\n",num1);
for(i=0; i<num1; i++)
{
printf("*");
}
printf("\n");
}
void barplot(int num1)
{
char s[BUFSIZ];
memset(s,'*',BUFSIZ);
printf("%.*s",num1%BUFSIZ,s);
}
I wonder why it has not been mentioned that standard c does not allow variable length arrays. You can do variable length arrays in C99 (ISO/IEC 9899:1999) but they are not part of C++ or standard C. It might be supported by some compilers but there is always a risk.
Besides i am certain that above question being an assignment, was given with the intention that size determined at run time should be handled using dynamic allocation such as malloc.
char arr[SIZE]; // size has to be a constant value or a variable with const modifier
Size cannot be determined at run time for the above syntax.
You should use malloc as a standard practice
char *arr = malloc(n1);
This needs to be freed latter too
free(arr);

Resources