Segmentation fault when calling strcpy - c

I was trying to use strncpy and then strcpy and vice versa, but I kept receiving a segmentation fault during runtime. I thought this was because of an logical error in the functions, but I switched their places and only the first one would execute.
#include <stdio.h>
#include <string.h>
int main(void)
{
char c = ' ', sentence[50], *pointer_to_string;
pointer_to_string = &sentence[0];
int index = 0;
printf("Please enter a sentence:");
while ((c = getchar()) != '\n')
{
sentence[index] = c;
index++;
}
sentence[index] = '\0';
char *string_copy1, *string_copy2;
strncpy(string_copy1, pointer_to_string, 5);
printf("strncpy(string_copy1, pointer_to_string, 5):\n");
printf("%s\n", string_copy1);
strcpy(string_copy2, pointer_to_string);
printf("strcpy(string_copy2, pointer_to_string):\n");
printf("%s\n", string_copy2);
}

See documentation:
char *strcpy(char *dest, const char *src);
The first argument is a pointer to the destination buffer. But your pointers are not initialized:
char *string_copy1, *string_copy2;
Therefore, pointers contain some garbage values. And strcpy() writes to the memory that does not belong to your program. It causes segmentation fault.
Do
char string_copy1[50] = { 0 };
char string_copy2[50] = { 0 };
Filling them with zeros is neccessary to avoid problems with strncpy():
If there is no null byte among the first n bytes of src, the string placed in dest will not be null-terminated.

Related

Add a character to a character pointer which is initialized with a string in c [duplicate]

This question already has answers here:
How can I correctly assign a new string value?
(4 answers)
Closed 2 years ago.
I declared a character pointer and allocated memory dynamically and initialized it with a string now i want to add character to the pointer. I tried the following code but it is giving segmentation fault(core dumped) error.
#include <stdio.h>
int main()
{
char *ch;
ch = (char *)malloc(sizeof(char)*32);
ch = "hello";
ch[5] = 'k';
ch[6] = '\0';
printf("%s", ch);
return 0;
}
Yes you have allocated 32 chars for ch pointer. But right on the next line you're reassigning another statically allocated string to it which overrides the pointer to the dynamic memory that was stored in ch.
ch = (char *)malloc(sizeof(char)*32);
ch = "hello";
The result of this is, you lose the handle to the dynamic memory and now you have no way of freeing that memory with free().
If you want to assign "hello" to ch, you can do it with the strcpy function define in <string.h>.
#include <stdio.h>
#include <string.h>
int main()
{
char *ch;
ch = (char *)malloc(sizeof(char)*32);
// ch = "hello";
strcpy(ch, "hello");
ch[5] = 'k';
ch[6] = '\0';
printf("%s", ch);
free(ch);
return 0;
}
Strcpy just iterates through the array and assigns every character one by one. Also never forget to free the dynamic memory allocated.

C remove special characters from string

I am very new to C, and I have created a function that removes special characters from a string and returns a new string (without the special characters).
At first glance, this seemed to be working well, I now need to run this function on the lines of a (huge) text file (1 Million sentences). After a few thousand lines/sentences (About 4,000) I get a seg fault.
I don't have much experience with memory allocation and strings in C, I have tried to figure out what the problem with my code is, unfortunately without any luck.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
char *preproccessString(char *str) {
// Create a new string of the size of the input string, so this might be bigger than needed but should never be too small
char *result = malloc(sizeof(str));
// Array of allowed chars with a 0 on the end to know when the end of the array is reached, I don't know if there is a more elegant way to do this
// Changed from array to string for sake of simplicity
char *allowedCharsArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// Initalize two integers
// i will be increased for every char in the string
int i = 0;
// j will be increased every time a new char is added to the result
int j = 0;
// Loop over the input string
while (str[i] != '\0') {
// l will be increased for every char in the allowed chars array
int l = 0;
// Loop over the chars in the allowed chars array
while (allowedCharsArray[l] != '\0') {
// If the char (From the input string) currently under consideration (index i) is present in the allowed chars array
if (allowedCharsArray[l] == toupper(str[i])) {
// Set char at index j of result string to uppercase version of char currently under consideration
result[j] = toupper(str[i]);
j++;
}
l++;
}
i++;
}
return result;
}
Here is the rest of the program, I think the problem is probably here.
int main(int argc, char *argv[]) {
char const * const fileName = argv[1];
FILE *file = fopen(fileName, "r");
char line[256];
while (fgets(line, sizeof(line), file)) {
printf("%s\n", preproccessString(line));
}
fclose(file);
return 0;
}
You have several problems.
You're not allocating enough space. sizeof(str) is the size of a pointer, not the length of the string. You need to use
char *result = malloc(strlen(str) + 1);
+ 1 is for the terminating null byte.
You didn't add a terminating null byte to the result string. Add
result[j] = '\0';
before return result;
Once you find that the character matches an allowed character, there's no need to keep looping through the rest of the allowed characters. Add break after j++.
Your main() function is never freeing the results of preprocessString(), so you might be running out of memory.
while (fgets(line, sizeof(line), file)) {
char *processed = preproccessString(line);
printf("%s\n", processed);
free(processed);
}
You could address most of these problems if you have the caller pass in the result string, instead of allocating it in the function. Just use two char[256] arrays in the main() function.
int main(int argc, char *argv[])
{
char const* const fileName = argv[1];
FILE* file = fopen(fileName, "r");
char line[256], processed[256];
while (fgets(line, sizeof(line), file)) {
processString(line, processed);
printf("%s\n", processed);
}
fclose(file);
return 0;
}
Then just change the function so that the parameters are:
void preprocessString(const char *str, char *result)
A good rule of thumb is to make sure there is one free for every malloc/calloc call.
Also, a good tool to keep note of for the future is Valgrind. It's very good at catching these kinds of errors.
There are some major issues in your code:
the amount of memory allocated is incorrect, sizeof(str) is the number of bytes in a pointer, not the length of the string it points to, which would also be incorrect. You should write char *result = malloc(strlen(str) + 1);
the memory allocated in preproccessString is never freed, causing memory leaks and potentially for the program to run out of memory on very large files.
you do not set a null terminator at the end of the result string
Lesser issues:
you do not check if filename was passed nor if fopen() succeeded.
there is a typo in preproccessString, it should be preprocessString
you could avoid memory allocation by passing a properly sized destination array.
you could use isalpha instead of testing every letter
you should cast the char values as unsigned char when passing them to toupper because char may be a signed type and toupper is undefined for negative values except EOF.
there are too many comments in your source file, most of which are obvious but make the code less readable.
Here is a modified version:
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
// transform the string in `str` into buffer dest, keeping only letters and uppercasing them.
char *preprocessString(char *dest, const char *str) {
int i, j;
for (i = j = 0; str[i] != '\0'; i++) {
if (isalpha((unsigned char)str[i])
dest[j++] = toupper((unsigned char)str[i]);
}
dest[j] = '\0';
return dest;
}
int main(int argc, char *argv[]) {
char line[256];
char dest[256];
char *filename;
FILE *file;
if (argc < 2) {
fprintf(stderr, "missing filename argument\n");
return 1;
}
filename = argv[1];
if ((file = fopen(filename, "r")) == NULL) {
fprintf(stderr, "cannot open %s: %s\n", filename, strerror(errno));
return 1;
}
while (fgets(line, sizeof(line), file)) {
printf("%s\n", preprocessString(dest, line));
}
fclose(file);
return 0;
}
The following proposed code:
cleanly compiles
performs the desired functionality
properly checks for errors
properly checks for length of input string parameter
makes use of characteristic of strchr() also checking the terminating NUL byte
limits scope of visibility of local variables
the calling function is expected to properly cleaning up by passing the returned value to free()
the calling function is expected to check the returned value for NULL
informs compiler the user knows and accepts when an implicit conversion is made.
moves allowedCharsArray to 'file static scope' so does not have to be re-initialized on each pass through the loop and marks as 'const' to help the compiler catch errors
and now the proposed code: (note: edited per comments)
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
char *preproccessString(char *str)
{
// Create a new string of the size of the input string, so this might be bigger than needed but should never be too small
char *result = calloc( sizeof( char ), strlen(str)+1);
if( !result )
{
perror( "calloc failed" );
return NULL;
}
// Array of allowed chars
static const char *allowedCharsArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// Loop over the input string
for( int j=0, i=0; str[i]; i++)
{
if( strchr( allowedCharsArray, (char)toupper( str[i] ) ) )
{
// Set char at index j of result string to uppercase version of char currently under consideration
result[j] = (char)toupper(str[i]);
j++;
}
}
return result;
}
I think the problem is you are using malloc which allocates memory from the heap and since you are calling this function again and again you are running out of memory.
To solve this issue you have to call the free() function on the pointer returned by your preprocessString function
In your main block
char *result=preprocessString(inputstring);
//Do whatever you want to do with this result
free(result);

Truncating string causes segmentation fault

I would like to write a function in C that truncates an input string to 32 chars, but the code below gives me a segmentation fault. Could anyone explain why it is so?
void foo (char *value){
if (strlen(value)>32) {
printf("%c\n", value[31]); // This works
value[31] = '\0'; // This seg faults
}
}
If you call your function like this:
char str[] = "1234567890123456789012345678901234567890";
foo(str);
It will work fine. But if you call it like this:
char *str = "1234567890123456789012345678901234567890";
foo(str);
That can cause a segfault.
The difference here is that in the former case str is a char array, while in the latter case str is a pointer to a string constant. A string constant typically lives in a read only section of memory, so attempting to modify it causes the core dump.
Your program should be something like this :
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void foo(char **value) {
if (strlen(*value)>32) {
printf("%c\n", (*value)[32]);
(*value)[32] = '\0'; // You want the string length to be 32, so set 32th character to '\0' so 32 characters will be from 0 to 31
}
}
int main() {
char *str;
str = malloc(100); // Change 100 to max possible length of string user can enter
printf("Enter string : ");
scanf("%s", str);
foo(&str);
printf("Truncated string is %s\n", str);
free(str);
return 0;
}

Segfault in C program, malloc call

I am writing a program that takes a list of path ( environmental variable), splits the paths and prints it. When compiling it I get a segfault. The following is my output on GDB :
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400eb0 in dest (name=0x7fffffffbce0 "PATH") at executables.c:100
100 dest[i] = malloc(srclen+1);
On valgrind:
==21574== 1 errors in context 2 of 3:
==21574== Use of uninitialised value of size 8
==21574== at 0x400EB0: dest (executables.c:100)
==21574== by 0x400B5B: main (main.c:9)
This is my function:
char** dest(char *name){
int i=0;
char *vp;
const char s[2]=":";
char *token;
char **dest;
name[strlen(name)-1]='\0';
vp=getenv(name);
if(vp == NULL){
exit(1);
}
token =strtok(vp,s);
while( token != NULL ){
size_t srclen = strlen(token);
dest[i] = malloc(srclen+1);
strcpy(dest[i], token);
token = strtok(NULL, s);
i++;
}
dest[i]=NULL;
return dest;
}
And this is my main:
#include "executables.h"
int main(int argc, char **argv){
char *path;
char name[BUFSIZ];
printf("enter name of environment variable:\n");
fgets(name,BUFSIZ,stdin);
char **p=dest(name);
int j=0;
while(p[j]!=NULL){
printf("%s\n",p[j]);
j++;
}
return(0);
}
Use strdup(). Saves steps (accounts for
'\0' too). You have to allocate some memory before hand for the approach you're using. Otherwise you might want a linked list and allocate packets instead of using the array pattern. When you say dest[i] = <ptr value> you're indexing to an offset of unallocated memory and storing something there, so it's a segvio.
#include <string.h>
#define MAXTOKENS 10000
char **get_dest(char *name) {
// Since dest has to be exposed/persist beyond this function all
// need dynamically allocate (malloc()) rather than stack allocate
// of the form of: char *dest[MAXTOKENS].
char *dest = malloc(MAXTOKENS * sizeof (char *)); // <--- need to allocate storage for the pointers
char *vp;
if ((vp = getenv(name)) == NULL)
exit(-1); // -1 is err exit on UNIX, 0 is success
int i = 0;
char *token = strtok(vp, ":");
while (token != NULL) {
dest[i] = strdup(token); // <=== strdup()
token = strtok(NULL, ":");
i++;
}
// dest[i] = NULL; // Why are you setting this to NULL after adding token?
return dest;
}
It's better if main() takes care of passing a proper null-terminated string to the get_dest() function because main is where the finicky fgets() is handled. Generally you want to do things locally where it makes the most sense and is most relevant. If you ever took your get_dest() function and used it somewhere where the strings were not read by fgets() it would just be a wasted step to overwrite the terminator there. So by initializing the char array to zeroes before fgets() you don't have to worry about setting the trailing byte to '\0'.
And finally probably not good to have your function name dest the same name as the variable it returns dest. In some situations having multiple symbols in your program with the same name can get you into trouble.
#include "executables.h"
int main(int argc, char **argv) {
char *path;
char name[BUFSIZ] = { 0 }; // You could initialize it to zero this way
printf("enter name of environment variable:\n");
// bzero(name, BUFSIZ); //... or you could initialize it to zero this way then
fgets(name, BUFSIZ, stdin);
char **p = get_dest(name);
int j = 0;
while(p[j] != NULL) {
printf("%s\n", p[j]);
j++;
free(p[j]); // like malloc(), strdup'd() strings must be free'd when done
}
free(p);
return 0;
}
dest[i] = malloc(srclen + 1);
You need to allocate memory for the pointer to char pointers (dest) as well as each char pointer stored in dest. In the code you provided, neither step is taken.
From the manpage of getenv:
Notes
...
As typically implemented, getenv() returns a pointer to a string
within the environment list. The caller must take care not to modify
this string, since that would change the environment of the process.
Your code violates that rule:
vp=getenv(name);
...
token =strtok(vp,s);
This is an illegal memory write operation.

C initials program returned "Segmentation fault"

I am working on a initials project where you enter a name and it prints the initials. When I try and combine the strings it returns Segmentation fault instead of the initials.
#include <stdio.h>
#include <stdlib.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
int main(void) {
printf("Name: ");
string name = GetString();
printf("\n");
int length = strlen(name);
string initials = "";
int arraylength = length + 1;
char string[arraylength];
string[0] = toupper(name[0]);
int count = 1;
for(int l = 1;l<=length;l++) {
if(name[l] == ' ') {
l++;
count++;
string[l] = toupper(name[l]);
}
}
count++;
string[count] = '\0';
for(int c = 0;c<=count;c++) {
strcat(initials, &string[c]);
}
printf("%s\n", initials);
}
That's why a string type would cause confusion, you make a pointer to a single char. And you then pass it to strcat() that's simply wrong.
A string, as expected by strlen() or strcat() or all str* functions, is not simple a char pointer which is what the type string in your code is.
In c a c-string is actually a sequence of bytes with the last byte being '\0', and it's not optional. You create a pointer to a single char and that is not the same as a string that I just described.
Any of the str* functions will try to find the '\0' but since you passed the address of a stack variable which is not an array, the behavior is undefined when any of these functions try to increment and dereference the passed pointer.
When you do understand how strings work in c you would see that using strcat() for the concatenation of many chunks of a large string together is not very efficient, you would also know that you just need to append a single char and that you can by simply using index notation, like
char string[8];
string[0] = 'E';
string[1] = 'x';
string[2] = 'a';
string[3] = 'm';
string[4] = 'p';
string[5] = 'l';
string[6] = 'e';
string[7] = '\0'; // The very necessary terminator

Resources