Can someone please explain me why I get "Segmentation fault..." and how to fix it on this bit of code?
#include<stdio.h>
int str_length(char *s) {
int length = 0, i;
for(i = 0; *s; i++) {
s++;
}
return i;
}
char *strdel(char *s, int pos, int n) {
int i;
char *p, str[] = "";
p = str;
for(i = 0; i < str_length(s) - n + 1; i++) {
if(i >= pos) {
*(p + i) = *(s + i + n);
}
else {
*(p + i) = *(s + i);
}
}
s = str;
return s;
}
int main() {
char *str = "abcdef";
printf("str_lengh: %d\n", str_length(str));
printf("strdel: %s\n", strdel(str, 1, 2));
return 0;
}
And I get this output:
str_lengh: 6
strdel: adef
Segmentation fault (core dumped)
Also, is there a better way to create a function:
char *strdel(char *s, int pos, int n);
that deletes the n characters from position pos than the one I did?
I think you are writing all over the stack here...
char *strdel(char *s, int pos, int n) {
int i;
char *p, str[] = "";
p = str; // p points to str which is "" and is on the stack with length 0.
for(i = 0; i < str_length(s) - n + 1; i++) {
if(i >= pos) {
*(p + i) = *(s + i + n); // now you are writing onto the stack past p
}
else {
*(p + i) = *(s + i);// now you are writing onto the stack past p
}
}
s = str; // now s points to space on stack
return s; // now you return a pointer to the stack which is about to disapear
}
Whenever you write past p, which is often, you are running into Undefined Behavior. UB
You are writing into space which has not been allocated on the heap or on the stack.
You can write a version of strdel that works only on s. Something like this if I understand strdel right: (roughly, not tested!, needs bounds checking on pos and n )
char *strdel(char *s, int pos, int n) {
char *dst = s + pos, *src = s + pos + n;
while(*src) {
*dst++ = *src++;
}
*dst = 0;
return s;
}
I'll throw in my solution for the second part as well. Here's my strdel
char * strdel(char * s, int pos, int n){
memmove(s + pos, s + pos + n, strlen(s) - pos - n + 1);
return s;
}
It doesn't copy, it doesn't do bounds checking and the return-value is rather redundant (as it's equal to the input s). So all-in-all it's very standard-C-library-like.
Warning! Cannot be used for string-constants as it modifies s (hence no const char * s).
To address the second part of your question, I would have written it something like this (assuming you're going to be passing in string constants and therefore must make a copy of the incoming string):
/*
* Returns a copy of the NUL terminated string at s, with the
* portion n characters long starting at position pos removed.
*/
char* strdel(char* s, int pos, int n)
{
int size = strlen(s);
char* t = malloc(size - n);
memcpy(t, s, pos);
memmove(t + pos, s + pos + n, size - n + 1);
return t;
}
Related
char *concat(char *num1, const char *num2, int index) {
int length1 = strlen(num1);
int length2 = strlen(num2);
int lengthNum = 0;
char *num = malloc(length1 + length2 + 1);
if (num == NULL) {
free(num);
return NULL;
}
// memcpy(num, num1, length1);
// memcpy(num + length1, num + index, length2 + 1);
for (int i = 0; i < length1; i++) {
num[lengthNum] = num1[i];
lengthNum++;
}
for (int i = index; i < length2; i++) {
num[lengthNum] = num2[i];
lengthNum++;
}
return num;
}
I tried to use memcpy, but than my program doesn't work correctly (copies wrongly, but valgrind doesn't show an error).
But when I use two for loops instead, it works properly, but than valgrind shows an error
uninitialised value was created by a heap allocation.
How to use properly memcpy in this case?
memcpy(num, num1, length1);
memcpy(num + length1, num2, length2 + 1);
Your program has multiple issues:
freeing a null pointer when malloc failed is useless (but harmless).
you allocate length1 + length2 + 1 bytes, which is most likely too large as you intend to copy from index in the second string.
you should use type size_t for the lengths and offsets.
you copy from num2 + index without checking that index is a valid offset inside the string num2.
you should set a null terminator at the end of the new string.
Here is a modified version:
#include <stdlib.h>
#include <string.h>
char *concat(const char *num1, const char *num2, size_t index) {
size_t length1 = strlen(num1);
/* skip index bytes in num2 */
while (index --> 0 && *num2)
num2++;
size_t length2 = strlen(num2);
char *num = malloc(length1 + length2 + 1);
if (num != NULL) {
size_t j = 0;
while (*num1) {
num[j++] = *num1++;
}
while (*num2) {
num[j++] = *num2++;
}
num[j] = '\0';
}
return num;
}
and using memcpy:
#include <stdlib.h>
#include <string.h>
char *concat(const char *num1, const char *num2, size_t index) {
size_t length1 = strlen(num1);
/* skip index bytes in num2 */
while (index --> 0 && *num2)
num2++;
size_t length2 = strlen(num2);
char *num = malloc(length1 + length2 + 1);
if (num != NULL) {
memcpy(num, num1, length1);
memcpy(num + length1, num2, length2 + 1);
}
return num;
}
concat returns a pointer to an allocation array. It is the responsibilty of the caller to free this object after use. For example:
#include <stdio.h>
int main() {
char *p = concat("Hello", "dear world", 4);
if (p != NULL) {
printf("%s\n", p);
free(p);
}
return 0;
}
I'm allocating memory for a string using malloc, then I execute qsort over that memory sorting the characters of the string.
I execute qsort several times copying new values to the allocated memory each time.
After that I try to free the memory but it crashes
It doesn't crash if I comment the qsort line
/**
* Iterates over b finding permutations of s
*
* #param s smaller string
* #param b bigger string
* #param locations array for the result
* #return number of locations
*/
int substring_permutations(const char *s, const char *b, int *locations) {
int s_len = (int) strlen(s);
char *sorted_sub_b = malloc((s_len + 1) * sizeof(char));
sorted_sub_b[s_len] = '\0';
char *sorted_s = malloc((s_len + 1) * sizeof(char));
sorted_s[s_len] = '\0';
sort_string(s, s_len, sorted_s);
int l = 0;
for (int i = 0; i < strlen(b) - s_len + 1; i++) {
sort_string(b + i, s_len, sorted_sub_b);
if (strcmp(sorted_s, sorted_sub_b) == 0) {
locations[l++] = i;
}
}
free(sorted_s);
free(sorted_sub_b); // Why does this crash?
return l;
}
void sort_string(const char *s, int s_len, char *sorted_s) {
memcpy(sorted_s, s, s_len * sizeof(char));
qsort(sorted_s, s_len * sizeof(char), sizeof(char), chrcmp);
}
int chrcmp(const void *a, const void *b) {
return *(char *) a - *(char *) b;
}
It crashes when executing the second free
Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)
EDIT: Adding the calling code
int main() {
const char *s = "abbc";
const char *b = "cbabadcbbabbcbabaabccbabc";
printf("%s\n", s);
printf("%s\n", b);
size_t s_len = strlen(s);
size_t b_len = strlen(b);
int *locations = malloc((b_len + 1 - s_len) * sizeof(char));
int permutations = substring_permutations(s, b, locations);
for (int i = 0; i < permutations; i++) {
int location = locations[i];
printf("%d ", location);
print_chars(b + location, s_len);
printf("\n");
}
free(locations);
return 0;
}
void print_chars(const char *c, size_t size) {
for (int i = 0; i < size; i++) {
printf("%c", c[i]);
}
}
EDIT 2: I see the problem now, it was in the calling code:
I had
int *locations = malloc((b_len + 1 - s_len) * sizeof(char));
instead of
int *locations = malloc((b_len + 1 - s_len) * sizeof(int));
Thank you #user5329483
I'm trying to create a function that will receive an array of strings and the size and will return a string made of the biggest ASCII value's letter of each word, and the size of the string has to be precised and I'm not allowed using operator [](which is my main issue).
so for:
char *strArr[SIZE] = { "hello", "and", "good", "morning" };
the function shall return a string with the word
"onor"
.
So i thought of creating a double for loop, first one will lead me into the location of each word in the array and the inside one will help me go through each word.
currently I'm having trouble finding the right format with my pointers to actually go through the letters of my first word.
I'm aware i haven't checked if my memory allocation is valid and also didn't free my memory yet as I'm trying to figure out whats wrong first.
char *bigLetters(char *str[], int size)
{
char *strNew = (char *)malloc((size + 1) * sizeof(char));
char max = 'a';
for (int i = 0; i < size; i++)
{
for (int j = 0; (*(str + i)+j) != NULL; j++)
{
if ((*(str + i) + j) >= max)
{
max = (*(str + i) + j);
}
}
*(strNew + i) = max;
}
*(strNew +(size+1)) = NULL;
return *(strNew);
}
void main()
{
char *strArr[SIZE] = { "hello", "and", "good", "morning" };
char *res = bigLetters(strArr, SIZE);
printf("The new string is --> %s\n", res);
system("pause");
}
It will be easier to use the pointers if you separate the string pointer from its character pointer. Also, the max needs to be reset for each string, and you were writing the final string terminator outside of the memory allocated. You also use NULL where you should be using the character '\0'.
Finally the function was returning the first character of the new string (which I later free).
#include <stdio.h>
#include <stdlib.h>
#define SIZE 4
char *bigLetters(char *str[], int size)
{
char *strNew = malloc(size + 1); // no cast or sizeof necessary
for (int i = 0; i < size; i++)
{
char ch;
char max = 'a'; // moved inside loop
char *ptr = *(str + i); // use a separate pointer
for (int j = 0; (ch = *(ptr + j)) != '\0'; j++) // pull out the character
{
if (ch > max) // >= is not necessary
{
max = ch;
}
}
*(strNew + i) = max;
}
*(strNew + size) = '\0'; // correct the bounds error
return strNew; // just the pointer not its target
}
int main(void) // correct signature
{
char *strArr[SIZE] = { "hello", "and", "good", "morning" };
char *res = bigLetters(strArr, SIZE);
printf("The new string is --> %s\n", res);
free(res); // clean up
system("pause");
}
Program output
The new string is --> onor
Press any key to continue . . .
If you didn't impose odd and unhelpful restrictions upon your coding, you'd be able to quickly see the problems with your code or even avoid making them in the first place. The problem is that the following statement makes no sense - you're comparing a char * with a char as you're only de-referencing str once.
if ((*(str + i) + j) >= max)
This is the same as writing
if ((str[i] + j) >= max)
which you can see the obvious mistake since what you're trying to write is the equivalent of
if ((str[i][j]) >= max)
which would be
if (*(*(str + i) + j) >= max)
Your compiler should be throwing up warnings because comparing between a pointer and an integer is rarely something you'd want to do.
You can use pointers as position indicators and advance them as needed.
#include <stdio.h>
#include <stdlib.h>
#define SIZE 4
char
biggest_ascii(char* str)
{
char c = 0;
int i;
for (i = 0; *str; str++)
if (*str > c)
c = *str;
return c;
}
int
main()
{
int i;
char* strArr[SIZE] = {"hello", "and", "good", "morning"};
char** ppch;// current string
char res_str[SIZE + 1] = {0};/* resulting string,
initilized to 0 to be 0-terminated */
char* pch;// current char position
for (i = 0, ppch = strArr, pch = res_str; i < SIZE; i++, ppch++, pch++)
*pch = biggest_ascii(*ppch);
printf("%s\n", res_str);
return 0;
}
First, (*(str + i)+j) isn't the good way.
You could replace all
(*(str + i) + j)
by :
str[i][j]
Then, you need to reset the max to "a", because it's 'o' when you leave the loop, so your condition become str[i][j] >= o which is not what you want. Do it before the second for.
And I would have used while instead of for for the first loop.
I edited your code and this version is working fine for me :
#include <stdlib.h>
char *bigLetters(char *str[], int size)
{
char *strNew = (char *)malloc((size + 1) * sizeof(char));
int i = 0;
while (i < size) {
char max = 'a';
for (int j = 0; str[i][j]; j++) {
if (str[i][j] >= max) {
max = str[i][j];
}
}
strNew[i] = max;
i++;
}
strNew[i] = '\0';
return strNew;
}
void main()
{
char *strArr[5] = { "hello", "and", "good", "morning"};
char *res = bigLetters(strArr, 4);
printf("The new string is --> %s\n", res);
return 0;
}
str[i] is equivalent to *(str + i) and str[i][j] is equivalent to *(*(str + i) + j).
In your code you are using (*(str + i) + j) which is incorrect.
When char *[] passed to function, it will decay to char **. So, in bigLetters(), you can give char **str as the parameter. Also, it is inline with you requirement - not allowed using operator [].
Instead of hardcoding the dimension SIZE in char *strArr[SIZE], you can give the empty [] and let the compiler assign the dimension based on the size of initializer. In your case, size of initializer is 4 as you have given 4 strings in the strArr initializer. You can compute the size of strArr like this:
sizeof(strArr)/sizeof(strArr[0]);
You can do:
#include <stdio.h>
#include <stdlib.h>
char *bigLetters(char **str, size_t size) {
char *strNew = calloc(size + 1, 1); // sizeof(char) is always 1
// calloc will initialize all bytes in the allocated storage to zero.
// You dont need to add the null terminating character at the end of strNew
if (strNew == NULL)
exit(EXIT_FAILURE);
for (size_t i = 0; i < size; i++) {
for (size_t j = 0; *(*(str + i)+j) != '\0'; j++) {
if (*(*(str + i) + j) > *(strNew + i)) {
// You can directly fill the allocated memory with biggest ASCII
*(strNew + i) = *(*(str + i) + j);
}
}
}
return strNew;
}
int main(void) {
char *strArr[] = { "hello", "and", "good", "morning" };
char *res = bigLetters(strArr, sizeof(strArr)/sizeof(strArr[0]));
if (res != NULL) {
printf("The new string is --> %s\n", res);
free (res);
}
else
printf("bigLetters returned NULL\n");
return 0;
}
Note that void return type main() is not as per standard. Instead, you should use int as return type of main().
I have created two arrays that need to be concatenated after the second array (y in this case) has been rotated. However I want to rotate only the last 4 bytes of this array. This is my code:
char x[]={"hello"};
char y[]={"goodmorning"};
char combine[20];
strcpy(combine, x);
strcat(combine, y);
printf(combine);
Here before the concatenation into combine I want to do the rotation operation.
before rotation
combine= hellogoodmorning
after rotation
combine= gninhellogoodmor
I have tried to look for a logic to do this online but could not find anything specific. Can anybody please help.
void strRev(char *s)
{
char temp, *end = s + strlen(s) - 1;
while( end > s)
{
temp = *s;
*s = *end;
*end = temp;
--end;
++s;
}
}
char x[]={"hello"};
char y[]={"goodmorning"};
char combine[20];
strcpy(combine, x);
strcat(combine, y);
strRev(combine);
strRev(combine+4);
printf(combine);
I use
#define swap(a, b) { a ^= b; b ^= a; a ^= b; }
void reverse(char * s, int beg, int end) {
while (beg < end) {
swap(s[beg], s[end]);
++beg, --end;
}
}
void rotate(char * s, int k) {
if (!s || !*s) return;
int len = strlen(s);
k %= len;
reverse(s, 0, len - 1);
reverse(s, 0, k - 1);
reverse(s, k, len - 1);
}
and call rotate(combine, 4); to rotate 4 bytes in combine.
Try something like this shown below. I use strncpy instead of strcpy() and strcat(). Try to debug for better understanding. Run Live.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ROTATION_LEN 4
int main() {
char x[] = { "hello" };
char y[] = { "goodmorning" };
char c;
char combine[20] = {0}; // init with null
char * com = combine;
int i;
int leny = strlen(y);
int lenx = strlen(x);
for (i = 0; i < ROTATION_LEN; ++i) {
c = y[leny -1 - i];
combine[i] = c;
}
com += ROTATION_LEN; // forward address of combine by ROTATION_LEN
strncpy(com, x, lenx);
com += lenx; // forward address of combine by x length
strncpy(com, y, leny - ROTATION_LEN);
printf(combine);
return 0;
}
Output:
gninhellogoodmor
If you define a function like this:
void rotate_last_four(char *string)
{
char old_four[4];
char new_four[4];
strncpy(old_four, string + strlen(string) - 4, 4);
new_four[0] = old_four[3];
new_four[1] = old_four[2];
new_four[2] = old_four[1];
new_four[3] = old_four[0];
memmove(string + 4, string, strlen(string) - 4);
strncpy(string, new_four, 4);
}
Then you only need to add this line to your code before printing combine:
rotate_last_four(combine);
And the output is: gninhellogoodmor
I'm trying to replace ' ' (space) with '___' (triple underscore) in C.
Here is my code:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
int main()
{
char *a = "12 34 56";
int a_l = strlen(a);
printf("str1: \"%s\" (%d)\n", a, a_l);
char *b = "___";
int b_l = strlen(b);
printf("str2: \"%s\" (%d)\n", b, b_l);
for (int i = 0; i < a_l; i++) {
if (a[i] == ' ') {
char *o = malloc(a_l + b_l);
strncpy(o, a, i);
strncpy(o + i, b, a_l);
//strncpy help
printf("out: \"%s\"\n", o);
}
}
return 0;
}
I think that it is right so far, but I need to replace the comment line with correct strncpy (take the rest of string a (excluding space) and append it to string o). So the output should be like this:
str1: "12 34 56" (8)
str2: "___" (3)
out: "12___34 56"
out: "12 34___56"
If there are other mistakes in my code, please tell me.
UPD: This shouldn't replace all spaces in a loop. If the source string contains 8 spaces, there should be 8 lines printed and in each line only one space should be replaced.
You are overcomplicating this so much that I just TL;DR.
Some remarks that you might surely want to read, learn, embrace well and use:
I. int is not for string lengths and stuff. size_t is for string lengths and stuff.
II. String literals cannot be modified, so using the legacy char * type for assigning them to a variable is no good by any means, const-qualify that poor pointer base type.
III. Use VLAs instead of malloc() if dynamic memory management is not really needed (we're not living in 1989 anymore).
IV. NUL-terminate your strings because C stdlib routines expect you to do so.
int main()
{
const char *in = "foo bar baz";
int nspc = 0;
for (const char *p = strchr(in, ' '); p; p = strchr(p + 1, ' '))
nspc++;
char buf[strlen(in) + nspc * 2 + 1];
memset(buf, 0, sizeof(buf));
const char *s = in;
for (const char *p = strchr(s, ' '); p; p = strchr(s, ' ')) {
strncat(buf, s, p - s);
strcat(buf, "___");
s = p + 1;
}
const char *end = in + strlen(in);
strncat(buf, s, end - s);
printf("%s\n", buf);
return 0;
}
You can try this one. The problem comes from the fact that a_l + b_l in your malloc is always the same value. It doesn't affect by number of spaces.
int count = 0, index = 0;
for (int i = 0; i < a_l; ++i) {
if (a[i] == ' ') {
count++;
}
}
const char *o = malloc(a_l + 2 * count + 1); // 2 is because you add 3 new symbols, but remove 1 so 3 - 1 = 2
memset(o, 0, sizeof(o));
for (int i = 0; i < a_l; ++i) {
if (a[i] != ' ')
o[index++] = a[i];
else {
o[index++] = '_';
o[index++] = '_';
o[index++] = '_';
}
}
Without using library function!!!
while(*string)
{
if(*string=='\\')
{
*string++;
while(repl_len--)
*dest++ = *repl_string++;
}
else
{
*dest++ = *string++;
}
repl_string = temp_repl_string;
repl_len = temp_repl_len;
}
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
size_t my_strlen(const char *str, size_t *spc){
size_t len;
*spc = len = 0;
while(*str){
++len;
if(*str++ == ' ')++*spc;
}
return len;
}
int main(void){
char *a = "12 34 56";
size_t spc;
int a_l = my_strlen(a, &spc);
printf("str1: \"%s\" (%d)\n", a, a_l);
char *b = "___";
int b_l = strlen(b);
printf("str2: \"%s\" (%d)\n", b, b_l);
char *p, *o = malloc(a_l - spc + spc * b_l + 1);
p=o;
for (int i = 0; i < a_l; i++) {
if(a[i] == ' ') {
strncpy(p, b, b_l);
p += b_l;
} else {
*p++ = a[i];
}
}
*p = '\0';
printf("out: \"%s\"\n", o);
free(o);
return 0;
}
I see that many answers have been added, but this may have been done very simply with a single loop. Since the string is very short, you can sacrifice memory over CPU and allocate an array 3 times +1 bigger than the original string, and be sure that it won't be overflowed:
const char* string= "12 34 56";
size_t length= strlen(string);
char result[length*3 +1];
unsigned int index= 0;
memset(result, '\0', length*3+1);
for(int i=0; i<length; i++)
{
if(string[i]!= ' ')
{
result[index++]= string[i];
}
else
{
strcat(result,"___");
index+= 3;
}
}
I found another thread and after reading the answers, I figured out that the right line should look like this:
strncpy(o + i + b_l, a + i + 1, a_l - i);
And after few fixes that were suggested in this thread my code looks like this:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
int main()
{
char *a = "12 34 56";
size_t a_l = strlen(a);
printf("str1: \"%s\" (%d)\n", a, a_l);
char *b = "___";
size_t b_l = strlen(b);
printf("str2: \"%s\" (%d)\n", b, b_l);
for (int i = 0; i < a_l; i++) {
if (a[i] == ' ') {
char *o = malloc(a_l + b_l);
strncpy(o, a, i);
strcpy(o + i, b);
strncpy(o + i + b_l, a + i + 1, a_l - i);
printf("out: \"%s\"\n", o);
free(o);
}
}
return 0;
}
And this prints the desired putput.