Why am I getting a Seg-Fa - c

So I apologize for the general question. I haven't been able to find anything that speaks to my specific case. If there is something out there and I missed it, I'm sorry.
I am writing a function that reverses a string. It's for a project that comes with some pretty specific guidelines. I'm not allowed to use any functions such as malloc, printf etc and my function needs to return the string that is passed in as an argument. The function needs to be prototyped as follows:
char *ft_strrev(char *str);
This is my funtction:
char *ft_strrev(char *str)
{
int i;
int j;
char c;
i = 0;
j = ;
c = '0';
while(str[j] != '\0')
j++;
while(i != j)
{
c = str[i];
str[i] = str[j];
str[j] = c;
i++;
j--;
}
}
When I call this in a main and test it with putstr https://github.com/kigiri/userpref/blob/master/ft_42/ft_putstr.c it compiles fine, but at runtime I get a seg fault.
What am I doing wrong?

There are two problems with your code (apart from this j =; stuff.
After the first while look j points to the '\0' after the end of the string rather than to the last character of the string.
Condition of the second look does handle the situation when j - i is odd initially. for example, if i is 0 and j is 1 initially, then, after first iteration, i will be 1 and j will be 0, so condition will still be true.
Here is fixed code:
char *ft_strrev (char *str)
{
int i = 0, j = 0;
while (str [j] != '\0') j++;
while (i < --j) {
char t = str [i];
str [i++] = str [j];
str [j] = t;
}
return str;
}

Related

print string based on the frequency of character in C

I was solving the question of leet code in C
Question:
Given a string s, sort it in decreasing order based on the frequency of the characters. The frequency of a character is the number of times it appears in the string.
Return the sorted string. If there are multiple answers, return any of them.
Example 1:
Input: s = "tree"
Output: "eert"
Explanation: 'e' appears twice while 'r' and 't' both appear once.
So 'e' must appear before both 'r' and 't'. Therefore "eetr" is also a valid answer.
I tried to use the different approach instead taking the array[255] and increasing the array value in specific char ASCII index. But I m getting segmentation fault. I not understand why I m getting segmentation voilation. Only assumption I made here is input str always be in UPPER CASE.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *frequencySort(char *s)
{
int strlenn = strlen(s);
int fq[strlenn];
// init with 1 because at least 1 time char occur in input str.
for (int i = 0; i < strlenn; i++)
{
fq[i] = 1;
}
// count freq of string and replace dublicate char with *
// ex: ABCDA => ABCD*
for (int i = 0; i < strlenn - 1; i++)
{
if (s[i] == '*')
{
continue;
}
for (int j = (i + 1); j < strlenn; j++)
{
if (s[i] == s[j])
{
fq[i]++;
s[j] = (char)'*'; // segmentation violation error shows here
fq[j] = 0;
}
}
}
// sort freqency by in decending order and str char
// ex: ABCDDDAA = freq[3, 3, 1, 1] = soredt str = [ A, D, B, C ]
for (int i = 0; i < strlenn - 1; i++)
{
for (int j = i + 1; j < strlenn; j++)
{
if (fq[i] < fq[j])
{
// swap
int temp = fq[i];
fq[i] = fq[j];
fq[j] = temp;
// swap string char
char temp1 = s[i];
s[i] = s[j]; // segmentation violation error shows here
s[j] = temp1;
}
}
}
char *result = (char *)calloc(strlenn + 1, sizeof(char));
int l = 0;
for (int i = 0; fq[i] != 0 && i < strlenn; i++)
{
int k = fq[i];
while (k > 0)
{
printf("%c", s[i]);
result[l++] = s[i];
k--;
}
}
result[l] = '\0';
return result;
}
int main()
{
char *s = "ABCDDDAA";
frequencySort(s);
return 0;
}
Thanks!
In frequencySort, you are modifying s (e.g.):
s[j] = (char)'*'; // segmentation violation error shows here
In main, the s argument comes from:
char *s = "ABCDDDAA";
frequencySort(s);
Here s is function scoped and goes on the stack.
But, because this is a pointer to a string literal, the actual string data goes into the .rodata section. This is mapped as read only. So, when we try to change it, we get a protection exception.
To fix this, define a string array:
char s[] = "ABCDDDAA";
frequencySort(s);
Now the literal data is [still] in the .rodata section. But, when main starts up, it is copied into the s array which is on the stack [which is writable].

Trying to remove characters of string B from string A in standard C

So if A="aBcDeFg" and B="BDF", the output should be "aceg".
My idea was to check one-by-one if character of A is equal with any character of B (A[0] vs B[0]/B[1]...B[n] and so on). Therefore if they do not match, a counter variable is incremented. If the counter is smaller than length of B, then this character is deleted and when the counter equals length of B, the character is moved in an other string.
My version looks like this, but is not working:
void remove_characters(char s[], char r[])
{
int k, i, j, l = 0;
char s_copy[20];
for (i = 0; s[i] != '\0'; i++){
for (j = 0; r[j] != '\0'; j++)
if (s[i] != r[j])
k++;
if (k = strlen(r)){
s_copy[l++] = s[i];
k = 0;
}
}
puts(s_copy);
}
void main()
{
char s1[20],s2[20];
printf("Enter the first string: ");
gets(s1);
printf("Enter the second string: ");
gets(s2);
remove_characters(s1,s2);
}
Any ideas where is the problem?
Any ideas where is the problem?
There's more than one.
UnholySheep mentioned if (k = strlen(r)); you meant == rather than =.
k is not initialized before use; this is to be done before the inner loop.
s_copy is not null terminated.
Here's an alternative implementation which utilizes the standard function strchr and modifies s, which has the advantages that no limit is imposed on the length of s and that the result is available to the caller rather than just printed:
void remove_characters(char s[], char r[])
{
char *t = s;
do if (*s && strchr(r, *s)) continue;
else *t++ = *s;
while (*s++);
}

Longest Substring Palindrome issue

I feel like I've got it almost down, but for some reason my second test is coming up with a shorter palindrome instead of the longest one. I've marked where I feel the error may be coming from, but at this point I'm kind of at a loss. Any direction would be appreciated!
#include <stdio.h>
#include <string.h>
/*
* Checks whether the characters from position first to position last of the string str form a palindrome.
* If it is palindrome it returns 1. Otherwise it returns 0.
*/
int isPalindrome(int first, int last, char *str)
{
int i;
for(i = first; i <= last; i++){
if(str[i] != str[last-i]){
return 0;
}
}
return 1;
}
/*
* Find and print the largest palindrome found in the string str. Uses isPalindrome as a helper function.
*/
void largestPalindrome(char *str)
{
int i, last, pStart, pEnd;
pStart = 0;
pEnd = 0;
int result;
for(i = 0; i < strlen(str); i++){
for(last = strlen(str); last >= i; last--){
result = isPalindrome(i, last, str);
//Possible error area
if(result == 1 && ((last-i)>(pEnd-pStart))){
pStart = i;
pEnd = last;
}
}
}
printf("Largest palindrome: ");
for(i = pStart; i <= pEnd; i++)
printf("%c", str[i]);
return;
}
/*
* Do not modify this code.
*/
int main(void)
{
int i = 0;
/* you can change these strings to other test cases but please change them back before submitting your code */
//str1 working correctly
char *str1 = "ABCBACDCBAAB";
char *str2 = "ABCBAHELLOHOWRACECARAREYOUIAMAIDOINEVERODDOREVENNGGOOD";
/* test easy example */
printf("Test String 1: %s\n",str1);
largestPalindrome(str1);
/* test hard example */
printf("\nTest String 2: %s\n",str2);
largestPalindrome(str2);
return 0;
}
Your code in isPalindrome doesn't work properly unless first is 0.
Consider isPalindrome(6, 10, "abcdefghhgX"):
i = 6;
last - i = 4;
comparing str[i] (aka str[6] aka 'g') with str[last-i] (aka str[4] aka 'e') is comparing data outside the range that is supposed to be under consideration.
It should be comparing with str[10] (or perhaps str[9] — depending on whether last is the index of the final character or one beyond the final character).
You need to revisit that code. Note, too, that your code will test each pair of characters twice where once is sufficient. I'd probably use two index variables, i and j, set to first and last. The loop would increment i and decrement j, and only continue while i is less than j.
for (int i = first, j = last; i < j; i++, j--)
{
if (str[i] != str[j])
return 0;
}
return 1;
In isPalindrome, replace the line if(str[i] != str[last-i]){ with if(str[i] != str[first+last-i]){.
Here's your problem:
for(i = first; i <= last; i++){
if(str[i] != str[last-i]){
return 0;
}
}
Should be:
for(i = first; i <= last; i++, last--){
if(str[i] != str[last]){
return 0;
}
}
Also, this:
for(last = strlen(str); last >= i; last--){
Should be:
for(last = strlen(str) - 1; last >= i; last--){

String tokenizer without using strtok()

I'm in the process of writing a string tokenizer without using strtok(). This is mainly for my own betterment and for a greater understanding of pointers. I think I almost have it, but I've been receiving the following errors:
myToc.c:25 warning: assignment makes integer from pointer without a cast
myToc.c:35 (same as above)
myToc.c:44 error: invalid type argument of 'unary *' (have 'int')
What I'm doing is looping through the string sent to the method, finding each delimiter, and replacing it with '\0.' The "ptr" array is supposed to have pointers to the separated substrings. This is what I have so far.
#include <string.h>
void myToc(char * str){
int spcCount = 0;
int ptrIndex = 0;
int n = strlen(str);
for(int i = 0; i < n; i++){
if(i != 0 && str[i] == ' ' && str[i-1] != ' '){
spcCount++;
}
}
//Pointer array; +1 for \0 character, +1 for one word more than number of spaces
int *ptr = (int *) calloc(spcCount+2, sizeof(char));
ptr[spcCount+1] = '\0';
//Used to differentiate separating spaces from unnecessary ones
char temp;
for(int j = 0; j < n; j++){
if(j == 0){
/*Line 25*/ ptr[ptrIndex] = &str[j];
temp = str[j];
ptrIndex++;
}
else{
if(str[j] == ' '){
temp = str[j];
str[j] = '\0';
}
else if(str[j] != ' ' && str[j] != '\0' && temp == ' '){
/*Line 35*/ ptr[ptrIndex] = &str[j];
temp = str[j];
ptrIndex++;
}
}
}
int k = 0;
while(ptr[k] != '\0'){
/*Line 44*/ printf("%s \n", *ptr[k]);
k++;
}
}
I can see where the errors are occurring but I'm not sure how to correct them. What should I do? Am I allocating memory correctly or is it just an issue with how I'm specifying the addresses?
You pointer array is wrong. It looks like you want:
char **ptr = calloc(spcCount+2, sizeof(char*));
Also, if I am reading your code correctly, there is no need for the null byte as this array is not a string.
In addition, you'll need to fix:
while(ptr[k] != '\0'){
/*Line 44*/ printf("%s \n", *ptr[k]);
k++;
}
The dereference is not required and if you remove the null ptr, this should work:
for ( k = 0; k < ptrIndex; k++ ){
/*Line 44*/ printf("%s \n", ptr[k]);
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void myToc(char * str){
int spcCount = 0;
int ptrIndex = 0;
int n = strlen(str);
for(int i = 0; i < n; i++){
if(i != 0 && str[i] == ' ' && str[i-1] != ' '){
spcCount++;
}
}
char **ptr = calloc(spcCount+2, sizeof(char*));
//ptr[spcCount+1] = '\0';//0 initialized by calloc
char temp = ' ';//can simplify the code
for(int j = 0; j < n; j++){
if(str[j] == ' '){
temp = str[j];
str[j] = '\0';
} else if(str[j] != '\0' && temp == ' '){//can omit `str[j] != ' ' &&`
ptr[ptrIndex++] = &str[j];
temp = str[j];
}
}
int k = 0;
while(ptr[k] != NULL){//better use NULL
printf("%s \n", ptr[k++]);
}
free(ptr);
}
int main(){
char test1[] = "a b c";
myToc(test1);
char test2[] = "hello world";
myToc(test2);
return 0;
}
Update: I tried this at http://www.compileonline.com/compile_c99_online.php
with the fixes for lines 25, 35, and 44, and with a main function that called
myToc() twice. I initially encountered segfaults when trying to write null characters
to str[], but that was only because the strings I was passing were (apparently
non-modifiable) literals. The code below worked as desired when I allocated a text buffer and wrote the strings there before passing them in. This version also could be modified to return the array of pointers, which then would point to the tokens.
(The code below also works even when the string parameter is non-modifiable, as long as
myToc() makes a local copy of the string; but that would not have the desired effect if the purpose of the function is to return the list of tokens rather than just print them.)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void myToc(char * str){
int spcCount = 0;
int ptrIndex = 0;
int n = strlen(str);
for(int i = 0; i < n; i++){
if(i != 0 && str[i] == ' ' && str[i-1] != ' '){
spcCount++;
}
}
//Pointer array; +1 for one word more than number of spaces
char** ptr = (char**) calloc(spcCount+2, sizeof(char*));
//Used to differentiate separating spaces from unnecessary ones
char temp;
for(int j = 0; j < n; j++){
if(j == 0){
ptr[ptrIndex] = &str[j];
temp = str[j];
ptrIndex++;
}
else{
if(str[j] == ' '){
temp = str[j];
str[j] = '\0';
}
else if(str[j] != ' ' && str[j] != '\0' && temp == ' '){
ptr[ptrIndex] = &str[j];
temp = str[j];
ptrIndex++;
}
}
}
for (int k = 0; k < ptrIndex; ++k){
printf("%s \n", ptr[k]);
}
}
int main (int n, char** v)
{
char text[256];
strcpy(text, "a b c");
myToc(text);
printf("-----\n");
strcpy(text, "hello world");
myToc(text);
}
I would prefer simpler code, however. Basically you want a pointer to the first non-blank character in str[], then a pointer to each non-blank (other than the first) that is preceded by a blank. Your first loop almost gets this idea except it is looking for blanks preceded by non-blanks. (Also you could start that loop at i = 1 and avoid having to test i != 0 on each iteration.)
I might just allocate an array of char* of size sizeof(char*) * (n + 1)/2 to hold the pointers rather than looping over the string twice (that is, I'd omit the first loop, which is just to figure out the size of the array). In any case, if ptr[0] is non-blank I would write its address to the array; then looping for (int j = 1; j < n; ++j), write the address of str[j] to the array if str[j] is non-blank and str[j - 1] is blank--basically what you are doing, but with fewer ifs and fewer auxiliary variables.
Less code means less opportunity to introduce a bug, as long as the code is clean and makes sense.
Previous remarks:
int *ptr = declares an array of int. For an array of pointers to char, you want
char** ptr = (char**) calloc(spcCount+2, sizeof(char*));
The comment prior to that line also seems to indicate some confusion. There is no terminating null in your array of pointers, and you don't need to allocate space for one, so possibly spcCount+2 could be spcCount + 1.
This also is suspect:
while(ptr[k] != '\0')
It looks like it would work, given the way you used calloc (you do need spcCount+2 to make this work), but I would feel more secure writing something like this:
for (k = 0; k < ptrIndex; ++k)
I do not thing that is what caused the segfault, it just makes me a little uneasy to compare a pointer (ptr[k]) with \0 (which you would normally compare against a char).

Help with reversing a string in C

I am trying to reverse a character string in C
Here is what I have
void reverse(char str[]) {
int i = 0;
int length;
// Get string length
for (i = 0; str[i] != '\0' ; ++i) {
length = i;
}
char reversed[1000];
int j;
j = 0;
// Reverse it
for (j = 0; j < length ; ++j) {
reversed[j] = str[length - j];
}
}
I know that reversed contains the string reversed, but I'm not sure how to modify the original str without throwing away data I need.
I also don't know how to set strto reversed without looping again.
Would it be acceptable to do another...
int m;
m = 0;
for (m = 0; m < length ; ++m) {
str[j] = reversed[j];
}
Usually I'd say this many loops smells, but I'm also still quite unfamiliar with the language so I'm not sure...
Update
Thanks for all the answers guys, and I appreciate the edits too!
I ended up going with this...
int main() {
char str[] = "Reverse me!";
int length;
for (length = 0; str[length] != '\0'; length++) {
}
printf("length => %d chars\n", length);
int j, k;
char c;
for (j = 0, k = length - 1; j < k; j++, k--) {
c = str[k];
str[k] = str[j];
str[j] = c;
}
printf("reversed => %s\n", str);
return 0;
}
Some things I now know...
There is a strlen() like in PHP. However, it has not been discussed in the book yet, plus I need to get familiar with null terminated strings.
A for loop can assign and do multiple things that are comma separated. I never knew this!
So asking was worthwhile :)
You want to do an in-place reversal. Here's a standard algorithm:
// taken from The C Programming Language
// by Brian Kernighan and Dennis Ritchie (K&R)
void reverse(char s[])
{
int c, i, j;
for (i = 0, j = strlen(s)-1; i < j; i++, j--) {
c = s[i];
s[i] = s[j];
s[j] = c;
}
}
Note that strlen pretty much replaces your original first loop. It's one of the many standard string manipulation routines available from string.h.
See also
Wikipedia/In-place algorithm
Wikipedia/string.h
Wikipedia/C Standard Library
You can use either of the two methods below, depending on whether you're comfortable with pointers or not. It will also be worthwhile looking at them side-by-side when you satrt learning about pointers so you can better understand how they map to each other.
This is a full program for testing purposes:
#include <stdio.h>
#include <string.h>
// The pointer version.
void reverse1 (char *str) {
char t; // Temporary char for swapping.
char *s = str; // First character of string.
char *e = &(s[strlen(s)-1]); // Last character of string.
// Swap first and last character the move both pointers
// towards each other. Stop when they meet or cross.
while (s < e) {
t = *s;
*s++ = *e;
*e-- = t;
}
}
// The array version.
void reverse2 (char *str) {
char t; // Temporary char for swapping.
int s = 0; // First character of string.
int e = strlen(str)-1; // Last character of string.
// Swap first and last character the move both pointers
// towards each other. Stop when they meet or cross.
while (s < e) {
t = str[s];
str[s++] = str[e];
str[e--] = t;
}
}
int main (void) {
char x[] = "This is a string for reversing.";
printf ("Original: [%s]\n", x);
reverse1 (x);
printf ("Reversed: [%s]\n", x);
reverse2 (x);
printf (" Again: [%s]\n", x);
return 0;
}
and the output is:
Original: [This is a string for reversing.]
Reversed: [.gnisrever rof gnirts a si sihT]
Again: [This is a string for reversing.]
Comments on your code:
void reverse(char str[]) {
int i = 0;
int length;
// Get string length
for (i = 0; str[i] != '\0' ; ++i) {
length = i;
}
Rather than copying the i to length every time you could just wait until the end.
size_t len = 0; // size_t is an unsigned integer that is large enough to hold the sizes
// of the biggest things you can have (32 bits on 32 bit computer,
// 64 bits on a 64 bit computer)
char * s = str;
while (*s) {
len++;
s++;
}
Though the compiler would probably be able to make this optimization for you.
You should know, though, that there is a standard string function strlen ( #include <string.h> )which will measure the length of a char string using the same general algorithm (look for the end) but is usually optimized for the target processor.
len = strlen(str);
Your code again:
char reversed[1000];
Using big arrays are good for learning and simple examples, but you can also allocate memory dynamically based on the size you now know you need. The standard function for doing this is malloc which is in stdlib.h (also in malloc.h). Memory allocated with this function should also be freed, though.
int * p = malloc( 8 * sizeof(int) ); // allocate an array of 8 ints
/* ... work on p ... */
free(p);
/* ... don't access the memory pointed to by p anymore ... */
p = 0;
There are also other functions in the malloc family. There's calloc, which allocates memory and clears sets it to 0. There is also a function called strdup (which isn't in standard C, but is very widely available in string.h) which takes a string and allocates a duplicate of it. It is really just:
char * strdup(const char * str) {
size_t len = strlen(str);
char * s = malloc(len+1);
if (!s) {
return s;
}
return strcpy(s,str); // This could have been memcpy since you know the size
// and memcpy might have been faster on many processors
}
Another useful memory allocation function is alloca (not in the C standard, but widely available and similar functionality is available with variable length arrays in C99). It is great, but works differently from malloc. It allocates memory that is only useable until the current function returns because this memory is allocated in the same way as memory for local variables (from the stack).
More of your code:
int j;
j = 0;
// Reverse it
for (j = 0; j < length ; ++j) {
reversed[j] = str[length - j];
}
The code:
void reverse_in_place(char * str, size_t len) {
size_t i, j;
for (i = 0, j = len - 1; i < j ; i++, j--) {
char a = str[i];
char z = str[j];
str[i] = z;
str[j] = a;
}
}
should swap the order of the string without making a copy of it. For strings with odd length it won't try to swap the middle char with itself.
Reversing a string in C using pointers
#include<stdio.h>
char *srcptr = "Hello!";
char *destptr;
unsigned int length = 0;
void main(void)
{
while(*(ptr++) != '\0')
{
length++;
}
//at the end of while loop, pointer points to end of string
while(length--)
{
*destptr++ = *ptr--;
}
//append null at the end
*destptr = '\0';
printf("%s",ptr);
}

Resources