Why Segmentation Faults occur? - c

I just started to learn C and need some helps. I already compiled my code and fixed all warnings that occur. However, when I run my program it says 'Segmentation Fault' and this is my code.
#include <stdio.h>
#include <string.h>
char *sorting(char word[51], int n)
{
for (int i = 0; i < n; i++) {
for (int j = i+1; j < n; j++) {
if (word[i] > word[j]) {
char temp = word[i];
word[i] = word[j];
word[j] = temp;
}
}
}
return word;
}
From above, I just sort the word in order to use in strcmp.
First I will read file that contains jumbled words. Next read dictionary's file. Then I will check whether two words are the same.
int main(int argc, char **dict, char **jambles)
{
const char *j = jambles[1];
FILE *jambles_file = fopen(j, "r");
char jambles_words[51];
while (fgets(jambles_words, sizeof(jambles_words), jambles_file)) {
int count = 0;
const char *d = dict[1];
FILE *dict_file = fopen(d ,"r");
char dict_words[51];
printf("%s", jambles_words);
while (fgets(dict_words, sizeof(dict_words), dict_file)) {
int length_jambles = strlen(jambles_words);
int length_dict = strlen(dict_words);
char *j_ = jambles_words;
char *d_ = dict_words;
const char *sort_jambles = sorting(j_, length_jambles);
const char *sort_dict = sorting(d_, length_dict);
if (length_jambles == length_dict) {
int compare = strcmp(sort_jambles, sort_dict);
if (compare == 0) {
printf("%s", dict_words);
count++;
}
}
else if (count == 0) {
printf("NO MACTHES");
}
}
printf("\n");
}
return 0;
}
I still don't know what are the mistakes of my code even I already search on the internet for the causes of Segmentation Fault.

I suspect the root cause is that you misunderstand how command-line arguments are passed to C programs. When you run ./a.out foo bar and it calls into int main(int argc, char **argv, char **envp), "foo" will be in argv[1] and "bar" will be in argv[2]. envp will just contain environment variables like "TERM=xterm" and "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin". You appear to think that "bar" will instead end up in envp[1], which is incorrect.
The more immediate cause is likely that because of the above, your call to fopen is failing due to a file called "TERM=xterm" or something not existing, and so returning NULL, which you then pass to fgets blindly. In general, it's Undefined Behavior to pass null pointers to any standard library function that doesn't specifically say what doing so will do.

Related

Why the segmentation fault + how can I get rid of it?

I typed these codes + I get a segmentation fault. I am trying to make my very own special version of strtol:
struct optional_int {int Value; char IsNull;};
struct optional_int StrToHex(char Str[]) {
const char Hex[0x10] = "0123456789ABCDEF";
unsigned int Chr = 0x00,i,j,Number = 0x00;
unsigned char IsNull, IsNegative;
if(Str[0x0] == '-') {
IsNegative = 0x1;
int N_C_Char = 0;
while( Str[N_C_Char] != '\0' ) {
Str[N_C_Char]=Str[N_C_Char+1];//right here
N_C_Char++;
}
}else{IsNegative=0;}
printf("%sfas", Str);
for(i = strlen(Str); i > 0; i--){
unsigned int Successes = 0x0;
for( j = 0; j < 0x10; j++ ) {
if( Str[Chr]==Hex[Chr]) {
Number+=((pow(0x10, i))*j);
Successes++;
}
}
if(Successes!=1) {
IsNull = 1;
}else{
IsNull = 0;
Number = 0;
}
Chr++;
}
if(IsNegative == 1) {
return (struct optional_int){ Number, IsNull};
}else{
return (struct optional_int){-Number, IsNull};
}
}
int main(int argc, const char *argv[]) {
printf("asdf %x\n", StrToHex("-535").Value);
}
Whenever I give it some negative numbers, it gave me a segmentation fault core dump but I have located the issue.
Ok, so I figured it out. The issue is indeed the string you pass to the function. When you write "-535" the string is allocated in the data section of the program and you are not allowed to write it. When the number is negative you try to modify that string by shifting the digits over the - sign. That's why it crashes on negative numbers only.
int main(int argc, const char *argv[]) {
char c[200];
strcpy(c, "-535");
printf("asdf %x\n", StrToHex(c).Value);
}
This snippet works for me in the main function. You will never be able to pass constant strings to the function or pointers that refer to this kind of strings:
char c[200] = "-535";
StrToHex(c);
will also crash.
You must provide a memory location where you have write permissions.
Another workaround to your issue would be to not change the string to delete the - but write your code to just ignore it :)

Test case failing at specific line. Manually works fine - C (needle in haystack)

I have a C program that takes arguments from the command line. Prints the arguments in reverse order. And finds the needle/substring in the haystack. I have the following code:
Dumb.c
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "Dumb.h"
int main(int argc, char **argv)
{
int i, j, flag = 0;
for (i = 1; i < argc; i++)
{
char needle[] = "dumb";
int length = strlen(argv[i]);
for (j = length - 1; j >= 0; j--)
{
printf("%c", argv[i][j]);
argv[i][j] = tolower(argv[i][j]);
}
char *pch = strstr(argv[i], echo);
if(pch)
{
flag = 1;
}
}
if (flag == 1)
{
printf("Dumb was found!\n");
}
return 0;
}
It works perfectly when I try to run it manually from command line using: ./a.out Dumb.
But when I try to use a special test case for it, it just crashes at this line: argv[i][j] = tolower(argv[i][j]);
Here is the code for the testing:
TestLauncher.c
int unit_test(int argc, char **argv);
int main(int argc, char **argv)
{
unit_test(argc, argv);
return 0;
}
Test.c
int __hide_main__(int argc, char **argv);
int unit_test(void)
{
int retval;
char **array;
array = malloc(sizeof(char *) * 2);
array[0] = "./a.out";
array[1] = "Dumb";
retval = __hide_main__(2, array);
free(array);
return retval;
}
When you use the string literal "Dumb", it is read-only, unlike the command-line arguments. To see this, try running the following and you should get the same error:
char *arr = "Dumb";
arr[0] = 'd';
To fix this, you should copy the value of argv into a new array rather than modifying it in-place.
But when I try to use a special test case for it, it just crashes at this line: argv[i][j] = tolower(argv[i][j]);
Your program is having undefined behavior as you are trying to modify the string literal. When a program is having undefined behavior, anything can happen like it may work as expected, it may crash etc.
Change this:
array[1] = "Dumb";
to this:
array[1] = strdup("Dumb");
It works perfectly when I try to run it manually from command line using: ./a.out Dumb.
From C Standards (5.1.2.2.1p2):
The parameters argc and argv and the strings pointed to by the argv array shall be modifiable by the program, and retain their last-stored values between program startup and program termination.
So, it is perfectly fine to modify the argument vector which contains the list of the arguments passed (including program name) when running from command line.
Hence the program is working fine when running from command line.
Also, in your program unit_test function declared as:
int unit_test(int argc, char **argv);
but in the definition the signature is not matching:
int unit_test(void)
The compiler must be giving conflicting types error for this or I believe its a typo while you have edited your program before posting.
Follow the good programming practice, always check the malloc return:
array = malloc(sizeof(char *) * 2);
if (NULL == array) {
fprintf (stderr, "Failed to allocate memory");
exit(EXIT_FAILURE);
}

imitate strcpy function in c using char pointers

I am try to write a user defined function which will do exactly what strcpy() library function do. But although there is no error, my program crashes and not copying second string to first string. What's wrong with this code and how to fix it?
#include<stdio.h>
#include<string.h>
int main(){
char *ch1="abcd";
char *ch2="efgh";
str_cpy(ch1,ch2);
}
str_cpy(char *c1,char *c2){
int i=0;
while(c1[i]!='\0'){
i++;
}
printf("%c",*(c1+3));
int k;
for(k=0;k<=i;k++){
*(c1+k)=*(c2+k);
}
}
String literals are generally put into read only area, that's why the program crashed when you are writing into c1. The destination string needs to be an array or allocated buffer:
char c1[5];
str_cpy(c1, c2);
Also, in the function, it looks you are copying c2 to c1, but you are counting the length of c1, you should count the length of c2 instead:
// copy string c2 to c1
void str_cpy(char *c1, const char *c2){
int i=0;
while(c2[i]!='\0'){
i++;
}
int k;
for(k=0;k<=i;k++){
*(c1+k)=*(c2+k);
}
}
Your program invokes undefined behavior because you are trying to write to a string literal. String literals can be stored in read only memory, which is probably the case on your system, hence causing a crash.
Note that your string copying function can perform the copy in a single loop:
char *str_cpy(char *c1, const char *c2) {
for (int i = 0;; i++) {
c1[i] = c2[i];
if (c1[i] == '\0')
return c1;
}
}
You can verify the behavior with a modified main:
#include <stdio.h>
char *str_cpy(char *c1, const char *c2) {
for (int i = 0;; i++) {
c1[i] = c2[i];
if (c1[i] == '\0')
return c1;
}
}
int main(void) {
char buf[20];
char *ch2 = "Hello world\n";
printf("%s\n", str_cpy(buf, ch2));
return 0;
}
Here is a possible rework of your code, which doesn't have to pre-define buffer size (c1). You simply pass the buffer address. Also, please note that such buffer has to be freed once used (for example, if declared in local scope, not in main()):
#include <stdio.h>
#include <stdlib.h>
char *str_cpy(char **c1, const char *c2) {
int i, size = 0;
for(i = 0; ; i++)
if(c2[i] == '\0')break;
size = i + 1;
if(!(*c1 = realloc(*c1,size*sizeof(char))))
return *c1;//or devise some more sophisticated error handling
for (i = 0;; i++) {
(*c1)[i] = c2[i];
if (c2[i] == '\0')
return *c1;
}
}
int main(void){
char *ch1 = malloc(1); //you're responsible for freeing it, once used
char *ch2 = "Hello, everybody in the neighborhood!";
printf("%s\n",str_cpy(&ch1,ch2));
free(ch1);
return 0;
}
Please, also note you don't need to #include <string.h>

How to copy an array of char pointer to another in C

I am trying to store an array of char pointer to another array of char pointer. I am getting segmentation fault for the same.
int main(int argc, const char* argv[])
{
int argcCpy = argc;
char* argvCpy[10] = {};
for(argcCpy = argc; argcCpy>0; argcCpy--)
{
argvCpy[argcCpy] = (char *) malloc(strlen(argv[argcCpy]));
memcpy(argvCpy[argcCpy], argv[argcCpy], strlen(argv[argcCpy]));
printf("\nCount: %d, string: %s", argcCpy, argvCpy[argcCpy]);
}
return 0;
}
I spent more than enough time to make this work but I am not able to do it. Also, the same kind of question is already asked which is also left unanswered. If anybody can let me know the working code for the same, it would be really so helpful.
Hoping this to be answered.
Link of the similar question left out unawnsered -- C Beginner - Copying a char *array to another char *array
Thanks.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, const char* argv[])
{
int argcCpy = argc;
char* argvCpy[10] = {};
if (argc > 9)
{
return 1;
}
for(int i = argc; i > 0; i--)
{
if (argv[i] == NULL)
{
argvCpy[i] = NULL;
}
else
{
argvCpy[i] = (char *) malloc(strlen(argv[i]) + 1);
if (argvCpy[i] != NULL)
{
strcpy(argvCpy[i], argv[i]);
}
}
}
for (int i = 0; i <= argcCpy; i++)
{
if (argvCpy[i] != NULL)
{
printf("Count: %d, string: %s\n", i, argvCpy[i]);
}
else
{
printf("Count: %d, string is null\n", i);
}
}
return 0;
}
Check argc is not too high.
argv[argc] is NULL, take this into account.
Use strcpy, and allocate enough room for the ending \0.
Edit: Second for loop to show content.
You must allocate one byte more for the terminating NUL:
Change
malloc(strlen(argv[argcCpy]);
to
malloc(strlen(argv[argcCpy] + 1);
and you also must copy one byte more with memcpy
Change
memcpy(argvCpy[argcCpy], argv[argcCpy], strlen(argv[argcCpy]));
to
memcpy(argvCpy[argcCpy], argv[argcCpy], strlen(argv[argcCpy]) + 1);
BTW you can replace
memcpy(argvCpy[argcCpy], argv[argcCpy], strlen(argv[argcCpy]) + 1);
by
strcpy(argvCpy[argcCpy], argv[argcCpy]);
which is simpler and more clear.
And last but not least replace
for(argcCpy = argc; argcCpy>0; argcCpy--)
by
for(argcCpy = argc - 1; argcCpy>0; argcCpy--)
The last element of the argv array is argv[argc-1].
But be aware that you'll run into problems if you have more then 10 command line arguments.

Null terminating char pointer

I am completely newbie in C.
I am trying to do simple C function that will split string (char array).
The following code doesn't work properly because I don't know how to terminate char array in the array. There are to char pointers passed in function. One containing original constant char array to be split and other pointer is multidimensional array that will store each split part in separate char array.
Doing the function I encountered obviously lots of hustle, mainly due to my lack of C experience.
I think what I cannot achieve in this function is terminating individual array with '\0'.
Here is the code:
void splitNameCode(char *code, char *output);
void splitNameCode(char *code, char *output){
int OS = 0; //output string number
int loop;
size_t s = 1;
for (loop = 0; code[loop]; loop++){
if (code[loop] == ':'){
output[OS] = '\0'; // I want to terminate each array in the array
OS ++;
}else {
if (!output[OS]) {
strncpy(&output[OS], &code[loop], s);
}else {
strncat(&output[OS], &code[loop], s);
}
}
}
}
int main (int argc, const char * argv[]) {
char output[3][15];
char str[] = "andy:james:john:amy";
splitNameCode(str, *output);
for (int loop = 0; loop<4; loop++) {
printf("%s\n", output[loop]);
}
return 0;
}
Here is a working program for you. Let me know if you need any explanation.
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
void splitNameCode(char *code, char **output) {
int i = 0;
char* token = strtok(code, ":");
while (token != NULL) {
output[i++] = token;
token = strtok(NULL, ":");
}
}
int main (int argc, const char *argv[]) {
char* output[4];
char input[] = "andy:james:john:amy";
splitNameCode(input, output);
for (int i = 0; i < 4; i++) {
printf("%s\n", output[i]);
}
return 0;
}
If I understand your intent correctly, you are trying to take a string like andy:james:john:amy and arrive at andy\0james\0john\0amy. If this is the case, then your code can be simplified significantly:
void splitNameCode(char *code, char *output){
int loop;
strncpy(code, output, strlen(code));
for (loop = 0; output[loop]; loop++){
if (output[loop] == ':'){
output[loop] = '\0'; // I want to terminate each array in the array
}
}
}

Resources