Segmentation fault in a well compiled C program - c

I am solving a problem on USACO. In the problem, I have to take two strings as inputs and calculate the numerical values modulo 47. If the values are same, then GO is to be printed otherwise STAY has to be printed. The initial numerical value will be calculated by taking the product of the numerical values of the alphabets ( 1 for A and similarily 26 for Z ) and then the final number will be calculated by using modulo.
My program is being compiled withour any error and running well on my computer. However, it is showing a segmentation fault as the execution error by the grader computer. The program and the output is as follows:-
Program:-
#include<stdio.h>
#include<string.h>
main()
{
int cal(char *ptr);
char *comet,*group;
int a,b;
scanf("%s",comet);
a=cal(comet);
scanf("%s",group);
b=cal(group);
if(a==b)
printf("GO");
else
printf("STAY");
return 0;
}
int cal(char *ptr)
{
int i=0,c,prod=1,mod;
while(ptr[i]!='\0')
{
if(ptr[i]>='A'&&ptr[i]<='Z')
{
c=ptr[i]-'#';
prod=prod*c;
i++;
}
}
mod=prod%47;
return mod;
}
OUTPUT:-
My question is how to pinpoint the segmentation fault. I have read about this fault but don't know what to do in this program. Any help would be great.

char *comet,*group;
int a,b;
scanf("%s",comet);
comet pointer is uninitialized. You need to allocate memory and makes comet points at this allocated memory otherwise scanf will write bytes in a random location which will likely crash your system.

Both comet and group are uninitialized pointers which do not have any memory allocated for storing the input strings.
Your program should be doing this at least. Increase the size of MAX_STRING_SIZE per your needs.
#define MAX_STRING_SIZE 100
char comet[MAX_STRING_SIZE];
char group[MAX_STRING_SIZE];
You still have the risk of buffer overflow with scanf. You can look at this post for some possible ways to avoid buffer overflow.

Your while is highly suspect: i is increased only if ptr[i] is an uppercase letter. What should happen if it isn't? How does If you have an ironclad guarantee that only uppercase letters will show up, you could write:
prod = 1;
while(*ptr) {
prod *= *ptr - 'A' + 1;
ptr++;
}
(Your ptr[i] - '#' had me scratching my head until I broke out ascii(7). I believe my version is clearer, and any halfway competent compiler will give the same code.)
Or, more idiomatically:
int cal(char *ptr)
{
int prod = 1;
while(*ptr)
prod *= *ptr++ - 'A' + 1;
return prod % 47;
}
Just be careful that the product does't overflow, perhaps do the modulus each character:
int cal(char *ptr)
{
int prod = 1;
while(*ptr) {
prod *= *ptr++ - 'A' + 1;
prod %= 47;
}
return prod;
}

You never allocate space for comet or group. Use malloc() or similar to set aside memory for those pointers, so that you can actually store something in what they point to.
#define MAX_STRING_LENGTH 256
...
char *comet, *group;
int a, b;
comet = NULL;
comet = malloc(MAX_STRING_LENGTH);
if (!comet) {
fprintf(stderr, "ERROR: Could not allocate memory to comet\n");
return EXIT_FAILURE;
}
scanf("%s",comet);
/* repeat for other pointers, as needed */
/* ... */
/* free up allocated memory at the end of the program to help prevent leaks */
free(comet);
comet = NULL;

"running well on my computer" this is not possible in your case as you are not using any compiler specific code (like getch for turbo c)
You didn't allocate memory for storing the string.The pointers comet and group don't point to anything.scanf requires an address to write the input but the pointers do not contain an address and that is why you are getting a segmentation fault.
You can allocate memory using malloc (or calloc) or you can define a character array.
The corrected code is
#include<stdio.h>
#include<string.h>
#define MAXLENGTH 100
int main()
{
int cal(char *ptr);
char comet[MAXLENGTH],group[MAXLENGTH];
int a,b;
scanf("%s",comet);
a=cal(comet);
scanf("%s",group);
b=cal(group);
if(a==b)
printf("GO");
else
printf("STAY");
return 0;
}
int cal(char *ptr)
{
int i=0,c,prod=1,mod;
while(ptr[i]!='\0')
{
if(ptr[i]>='A'&&ptr[i]<='Z')
{
c=ptr[i]-'#';
prod=prod*c;
i++;
}
}
mod=prod%47;
return mod;
}

Related

Why this code giving me a segmentation fault?

#include <stdio.h>
int main()
{
int i,a;
int* p;
p=&a;
for(i=0;i<=10;i++)
{
*(p+i)=i;
printf("%d\n",*(p+i));
}
return 0;
}
I tried to assign numbers from 0 to 10 in a sequence memory location without using an array.
You are trying to write to memory that it does not have permission to access.
The variable a is a local variable in the main function, and it is stored on the stack. The pointer p is initialized to point to the address of a. The code then attempts to write to the memory addresses starting at p and going up to p+10. However, these memory addresses are not part of the memory that has been allocated for the program to use, and so the program receives a segmentation fault when it tries to write to them.
To fix this issue, you can either change the loop condition to a smaller value, or you can allocate memory dynamically using malloc or calloc, and assign the pointer to the returned address. This will allow you to write to the allocated memory without causing a segmentation fault.
Like this:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i;
int* p = malloc(sizeof(int) * 11); // Allocate memory for 10 integers
if (p == NULL) { // Check for allocation failure
printf("Error allocating memory\n");
return 1;
}
for(i=0;i<=10;i++)
{
*(p+i)=i;
printf("%d\n",*(p+i));
}
free(p); // Free the allocated memory when you are done with it
return 0;
}
a is only an integer. not an array.
you need to declare it differently:
int i, a[10];
You can not. Memory of int is 4 bytes and you can store only single number in that memory.
for int: -2,147,483,647 to 2,147,483,647
for unsigned int: 0 to 4, 294, 967 295
There are other types you can use with different sizes, but if you want to put different numbers into one variable you need to use array.
int arr[10];
arr[0] = 0;
arr[1] = 5;
something like this.

malloc-> how much memory is allocated? [duplicate]

This question already has answers here:
I can use more memory than how much I've allocated with malloc(), why?
(17 answers)
Closed 9 years ago.
As I know that malloc allocate a specific number of bytes in the memory. However I am trying to use it and I allocate 4 bytes but it gives me NO error when I try to store more than 4 (up to 200 integers) elements in the array!! So in my code I don't need to use realloc!! I'm using Linux by the way. Finally I will pleased to hear any advice from you ... thanks in advance.
tmp.h :
#ifndef TMP_H
#define TMP_H
#define MAXLENGTH 4
#define GROWFACTOR 1.5
typedef struct stVector
{
int *vec;
int length;
int maxLength;
}Vector;
Vector newEmptyVector();
void addElement(Vector *vec, int elt);
#endif
tmp.c :
#include "stdio.h"
#include "stdlib.h"
#include "tmp.h"
Vector newEmptyVector()
{
Vector vec;
vec.vec = (int*) malloc(0);
printf("Allocating %d bytes\n", sizeof(int)*MAXLENGTH );
vec.length = 0;
vec.maxLength = MAXLENGTH;
return vec;
}
void addElement(Vector *vec, int elt)
{
/*if(vec->length == vec->maxLength)
{
vec->vec = (int*)realloc(vec->vec,sizeof(int)* vec->maxLength * GROWFACTOR);
vec->maxLength = vec->maxLength * GROWFACTOR;
}*/
vec->vec[vec->length++] = elt;
}
main.c :
#include"tmp.h"
int main(int argc, char const *argv[])
{
Vector vector = newEmptyVector();
printf("The length is %i and maxlength is ` `%i\n",vector.length,vector.maxLength);
addElement(&vector,5);
addElement(&vector,3);
addElement(&vector,1);
addElement(&vector,7);
printf("The length is %i and maxlength is ` `%i\n",vector.length,vector.maxLength);
addElement(&vector,51);
printf("The length is %i and maxlength is %i\n",vector.length,vector.maxLength);
for (int i = 0; i < 200; ++i)
{
addElement(&vector,i);
printf("The length is %i and maxlength is %i\n" ,vector.length, vector.maxLength);
}
return 0;
}
Using memory you haven't allocated invokes undefined behavior. Don't do that. In all likelyhood, Linux has give your program a page of memory, and you haven't overrun that yet. If you touch memory not allocated to your program the OS should cause your program to segfault. But it's possible that any other mallocing you do will also use parts of that page, and you'll end up corrupting your data.
Not having runtime checks for overrunning buffers is part of what makes C fast, but it puts more on the programmer not to do dumb things.
The fact that (simply because there is no bound checking in C) no error is raised does not mean that you can safely use memory outside requested bounds. You were lucky not to cause a segmentation fault, you have just fallen into a memory region that is not claimed by your malloc (let's say, it's not yours).
You can write there, but there is no guarantee that you won't be overwriting memory assigned to another malloc or, conversely, that the "extra" part will not be allocated to some other malloc. In your case, the memory region you are writing into appears not to be claimed (yet).
Regarding your specific issue:, I allocate 4 bytes but it gives me NO error when I try to store more than 4.
Keep in mind, something like:
int *anyVar = (int)malloc(0);
anyVar[0] = 12; //Will eventually invoke undefined behavior.
writing to memory you do not own will eventually invoke undefined behavior. The bad thing is that your results can seem good, and even repeatable for many runs of the code. But at some point, your code will fail.
This is how you should allocate: (by the way)
int numIntsInArray = 100;
int *anyVar = malloc(sizeof(int)*numIntsInArray);//note:do not cast output of malloc
anyVar[0] = 1;//first element of anyVar
anyVar[99] = 1000;//last element of anyVar
Do not forget to free all memory:
free(anyVar);
Other examples of undefined behavior in C & C++:
The examples of bad code below can be done, and you will likely get no compiler warnings, and may even get
expected results during run-time, but with this code, nothing is guaranteed. (exception: good examples)
char * p = "string"; // Badly formed C++11, deprecated C++98/C++03
p[0] = 'X'; // undefined behavior
Create an array instead:
char p[] = "string"; // Good
p[0] = 'X';
C++, you can create/use a standard string like this:
std::string s = "string"; // Good
s[0] = 'X';
Division by zero results in undefined behavior:
int x = 1;
return x / 0; // undefined behavior
Some pointer operations may lead to undefined behavior:
int arr[4] = {0, 1, 2, 3};
int* p = arr + 5; // undefined behavior
Leaving a non-void function without returning a value
int func(void)
{
//undefined behavior
}
Unspecified or implementation-defined behavior:
printf("%d %d\n", ++n, power(2, n)); //Bad
i = ++i + 1; //Bad
i = i + 1; // Okay

C program not printing

I have written the following program:
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
void inttobusn(int val, int n, char* bus)
{
int i;
unsigned int digit;
for (i=0; i < n; i++) {
digit = pow(2, (n-1-i));
if (digit <= val) {
val -= digit;
bus[i] = '1';
//printf("hello %c",bus[i]);
} else {
bus[i] = '0';
}
}
}
main(){
char* bus;
inttobusn(37,8,bus);
int i=0;
//printf("%s",bus);
for(i=0;i<12;i++){
printf("%c",bus[i]);
}
}
But on running it doesn't print the elements of the array bus. It doesn't print anything. I am unable to figure out what is wrong. Please could someone point out?
Your code is buggy! you don't allocate memory for the bus[] array, and are trying to access values at garbage location as e.g bus[i] = 0; -- Undefined Behavior in C standard, Undefined means you can't predict how your code will behave at runtime.
This code compiled because syntax-wise the code is correct but at runtime the OS will detect illegal memory access and can terminate your code. (interesting to note: as OS detects memory right violation by a process -- An invalid access to valid memory gives: SIGSEGV And access to an invalid address gives: SIGBUS). In the worst case your program may seem execute without any failure, producing garbage results.
To simply correct it define bus array as char bus[N]; else allocated memory dynamically using void* malloc (size_t size);
Additionally, suggestion to your from #Lochemage and #Ran Eldan:
You need to declare bus with a specific size, like char bus[12]. It has to be at least large enough to fit 12 chars because your for loop at the end is iterating through that many (and you can check your code working with this suggestion #codepade).
Also there is no return type to main() in your code, its should be int main(void).
There is no memory allocated to bus so this is an undefined behavior. Either write
char bus[some sufficient size];
or use malloc, realloc to reserve memory.
You didn't initialize you bus variable.
char* bus = malloc(8 * sizeof(char));

I'm using malloc and my program is crashing

Today I was messing around with malloc and integer pointer. The program is setup so it allocates a memory location to an integer pointer and then fills the memory location with bunch of integers like an array and then print all the integers. The problem is when ever it finishes running it crashes. And I suspect that malloc is causing the issue.
Here is the code
#include<stdio.h>
#include<stdlib.h>
int main(){
int *name,x;
char y;
name=malloc(sizeof(int));
for(x=0;x<500;x++){
name[x]=x;
}
for(x=0;x<500;x++){
printf("%d ",name[x]);
}
scanf("%c",&y);
free(name);
return 0;
}
please help.
Thanks!
name = malloc(sizeof(int));
is the problem. That way you can store only one int in the array. Try
name = malloc(sizeof(int) * 500);
instead.
Uh, "malloc()" isn't crashing your program.
You're crashing your program :)
SUGGESTIONS:
Check for "name=malloc()" returning NULL (i.e. check for errors).
Don't allocate space for 1 int ("sizeof(int)" is probably four bytes), then try to write 500 ints :)
Don't litter your code with "magic numbers" like "500" - use a constant instead.
SUGGESTED CHANGES:
#include<stdio.h>
#include<stdlib.h>
#define NELMS 500
int main(){
int *name = NULL,x;
char y;
name=malloc(sizeof(int) * NELMS);
if (!name) {
perror ("Unable to allocate memory!");
return 1;
}
for(x=0;x<NELMS;x++){
name[x]=x;
}
for(x=0;x<NELMS;x++){
printf("%d ",name[x]);
}
scanf("%c",&y);
free(name);
return 0;
}
You are allocating memory to store only one int. What you need is:
name=malloc(500*sizeof(int));

Why does this give a segmentation fault?

I'm stunned, why does this code give me a segmentation fault?
#include <stdio.h>
#define LIMIT 1500000
typedef struct {
int p;
int a;
int b;
} triplet;
int main(int argc, char **argv) {
int i;
triplet triplets[LIMIT];
for (i = 0; i < LIMIT; i++) {
triplets[i].p = 9; // remove this line and everything works fine
}
printf("%d\n", triplets[15].p);
return 0;
}
EDIT: After changing LIMIT to 150 I no longer get a segmentation fault, it prints random numbers instead.
EDIT2: Now I know what the site name stands for :) I made the array global and everything works fine now.
Stack overflow! Allocating 1500000 records at 12 bytes per record (assuming 4-byte int), requires more than 17 MB of stack space. Make your triplets array global or dynamically allocate it.
As to your edit - shrinking the array will probably stop the stack overflow, but your printf() call will still print uninitialized data - triplets[15].p could be anything at the time you print it out.
When you do
triplet triplets[LIMIT];
you're allocating that on the stack. Which is apparently too big for your system.
If you do
triplet* triplets=(triplet*)malloc(LIMIT*sizeof(triplet));
you'll allocate it on the heap and everything should be fine. Be sure to free the memory when you're done with it
free(triplets);

Resources