I am making a "simple" print out string, append string and remove section from a string. The append and new string works sometimes, sometimes it outputs nothing.
When i do:
char * temp = malloc(newSize);
It just stops outputting anything.
I have commented everything out in sections, trying to find the problem. Can't seem to find the problem, but google keeps coming up with "Heap Corruption".
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char * data;
int length;
} String;
int str_getLength(const char * characters)
{
int index = 0;
while (1)
{
if (characters[index] == '\0') break;
index++;
}
return index;
}
String str_new(const char * characters)
{
String result;
result.length = str_getLength(characters);
result.data = malloc(result.length);
memcpy(result.data, characters, result.length);
return result;
}
void str_append(String * str, const char * characters)
{
int charsLength = str_getLength(characters);
str->data = realloc(str->data, charsLength);
for (int i = 0; i < charsLength; i++) {
str->data[i + str->length] = characters[i];
}
str->length = str->length + charsLength;
}
void str_remove(String * str, int startIndex, int endIndex)
{
if (startIndex < 0 || endIndex > str->length || endIndex < startIndex) {
return;
}
int chunkSize = endIndex - startIndex;
int newSize = str->length - chunkSize;
char * temp = malloc(newSize);
// for (int i = 0; i < str->length; i++)
// {
// if (i < startIndex || i > endIndex) {
// temp[i] = str->data[i];
// }
// }
// free(str->data);
// str->length = newSize;
// str->data = temp;
}
}
int main()
{
String str = str_new("Hello, ");
printf("%s\n", str.data);
str_append(&str, "this is my first C application.");
printf("%s\n", str.data);
str_remove(&str, 0, 3);
printf("%s\n", str.data);
free(str.data);
return 0;
}
I expected it to output a modified string, it doesn't and sometimes it outputs nothing.
I am a beginner, sorry if it's a quick fix.
Apart from the blaze answer.
There are few more problems.
// for (int i = 0; i < str->length; i++)
// {
// if (i < startIndex || i > endIndex) {
// temp[i] = str->data[i];
// }
// }
You will access out of bound for temp.
You need to maintain separate index for temp.
char * temp = malloc(newSize+1);
int k=0;
for (int i = 0; i < str->length; i++)
{
if (i < startIndex || i > endIndex) {
temp[k++] = str->data[i];
}
}
temp[k] = '\0';
free(str->data);
str->length = newSize;
str->data = temp;
And
You are not null terminating the string after append.
str->data = realloc(str->data, str->length + charsLength +1); //current length + new length + \0
for (int i = 0; i < charsLength; i++) {
str->data[i + str->length] = characters[i];
}
str->data[i + str->length] = '\0'; //null terminate the new string
str->length = str->length + charsLength;
There are two problems with your reallocation. First of all, you're not assigning the result of the realloc to str->data, so if the memory was reallocated to a different place, tr->data points to invalid memory afterwards. Second, you're not adding the sizes of the string and the appended part, you're just taking the size of the part that you're appending.
This here
realloc(str->data, charsLength);
Should be:
str->data = realloc(str->data, charsLength + str->length + 1);
Related
Please, help with the code.
Requirement:
Write a function my_union that takes two strings and returns, without doubles, the characters that appear in either one of the strings.
Example:
Input: "zpadinton" && "paqefwtdjetyiytjneytjoeyjnejeyj"
Output: "zpadintoqefwjy"
My code:
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
char *my_union(char *a, char *b) {
char *str;
// Algorithm for excluding nonunique characters from string a(given in
// parameters).
str[0] = a[0];
int k = 1;
str[k] = '\0';
for (int i = 1; a[i] != '\0'; i++) {
bool is = true;
for (int j = 0; str[j] != '\0'; j++) {
if (str[j] == a[i]) {
is = false;
break;
}
}
if (is) {
str[k] = a[i];
k++;
str[k] = '\0';
}
} // In this case we are excluding excess character 'n' from "zpadinton", so
// str is equal to "zpadinto".
// Algorithm for adding unique characters from array b(given in parameters)
// into str.
for (int i = 0; b[i] != '\0'; i++) {
bool is = true;
for (int j = 0; str[j] != '\0'; j++) {
if (str[j] == b[i]) {
is = false;
break;
}
}
if (is) {
strncat(str, &b[i], 1);
}
}
return str;
}
The first algorithm is almost identical with second, but it doesn't work(. Mb I messed up with memory, give some advice, pls.
If you mean, get the unique characters from two strings and store them into a new string, try this code ;
First, you must allocate a memory for str. In your code, str is not pointing allocated memory location, so you will probably get segmentation fault.
int contains(const char * str,char c)
{
for (int i = 0; i < strlen(str); ++i)
if(str[i] == c)
return 1;
return 0;
}
char * my_union(char *a, char*b)
{
char * res = (char*)malloc(sizeof(char)*(strlen(a) + strlen(b)));
int pushed = 0;
for (int i = 0; i < strlen(a); ++i)
{
if(!contains(res,a[i])){
res[pushed] = a[i];
pushed++;
}
}
for (int i = 0; i < strlen(b); ++i)
{
if(!contains(res,b[i])){
res[pushed] = b[i];
pushed++;
}
}
return res;
}
int main(int argc, char const *argv[])
{
char string1[9] = "abcdefgh";
char string2[9] = "abegzygj";
char * result = my_union(string1,string2);
printf("%s\n", result);
return 0;
}
Also, do not forget the free the return value of my_union after you done with it.
char* putNum(Node* head)
{
char* str;
int size = 0;
int index = 0;
int lastNum, count = 0;
Node* temp = head->left;
lastNum = temp->info;
while (lastNum != 0)
{
lastNum = lastNum / 10;
count++;
}
if (head->info < 0)
{
size = abs(head->info) - 1;
size *= 5 + count;
str = (char*)malloc(sizeof(char) * size);
str[0] = '-';
index++;
}
else
{
size = head->info - 1;
size *= 5 + count;
str = (char*)malloc(sizeof(char) * size);
}
for (int i = 0; i < abs(head->info); i++)
{
char chars[5];
itoa(temp->info, chars, 10);
for (int j = 0; j < strlen(chars); j++)
{
str[index++] = chars[j];
}
temp = temp->left;
}
return str;
}
hi im learing c in visual studio and im tring to make a function that take a doubly linked list with a long number and put the number in a string. the error pops in the last '}' of the function.
I'm trying to create a function that can insert a char array of length len into a given index in a string type. However, it acts ways that it shouldn't.
When trying to insert at the end of the initial array, the contents of buf are inserted at the beginning of the string, in reverse order.
i.e. inserting world into Hello becomes dlrowHello
When trying to insert in the middle of the initial case, the output is worldHello
str->bytes.data is the array being modified.
str->bytes.usage is the length of that array.
bool string_insert(string_t * const str, size_t index,
const char * const buf, size_t len)
{
bool success = false;
uint8_t orig_size = str->bytes.usage;
uint8_t * temp;
if (str->len < index){
return false;
}
if(str->bytes.usage+len>=str->bytes.usage){
temp = malloc(sizeof(char) * (str->bytes.usage + len));
}
else {
temp = malloc(sizeof(char) * (str->bytes.usage));
}
if (temp == NULL){
success = false;
}
else{
if (index == 0){ //inserts at beginning
for (int k = 0; k < len; k++){
temp[k] = buf[k];
}
for (int j = len; j < str->bytes.usage+len; j++){
temp[j] = str->bytes.data[j - len];
}
}
else if (index == str->bytes.usage){ //inserts at end
for (int h = 0; h < str->bytes.usage; h++){
temp[h] = str->bytes.data[h];
}
for (int g = 0; g < len; g++){
temp[g+str->bytes.usage] = buf[g];
}
}
else{ //inserts in the middle
for (int i = 0; i < index; i++){
temp[i] = str->bytes.data[i];
}
for(int i = index; i < index + len; i++){
temp[i] = buf[i-index];
}
for(int i = index + len; i < str->bytes.usage+len; i++){
temp[i] = str->bytes.data[i-len];
}
}
string_free(str);
str->bytes.data = temp;
str->bytes.dim = 2*str->bytes.usage;
str->bytes.usage = orig_size+len;
success = true;
}
return success;
}
Basically, I just need to know if I'm blind and missing something obvious.
When index is 0, it is not in reverse order?
if (index == 0){ //inserts at beginning of array
for (int k = 0; k < len; k++){
temp[k] = buf[k];
changed to
if (index == 0){ //inserts at beginning of array
for (int k = 0; k < len; k++){
temp[k] = buf[len - k - 1];
// as i understand it:
// str->bytes.data = allocated memory
// str->bytes.dim = size of the allocated memory
// str->bytes.usage= size of the used memory
//
#define BLOCK_SIZE 32
bool string_insert(string_t * const str, size_t index,
const char * buf, size_t len)
{
int max_size;
int i;
char *start;
char *end;
char *tmp=str->bytes.data;
max_size=str->bytes.usage+len;
if(max_size>=str->bytes.dim){
// realloc by BLOCK_SIZE steps
max_size=((max_size/BLOCK_SIZE)+1)*BLOCK_SIZE;
tmp=realloc(tmp,max_size);
if(!tmp) return 0; //false
//update fields with new values
str->bytes.data=tmp;
str->bytes.dim=max_size;
}
start=tmp+index;
end=tmp+(str->bytes.usage);
//shift content after the insertion point
while(end>start){
end--;
*(end+len)=*end;
}
// no comments
strncpy (start,buf,len);
str->bytes.usage+=len;
return 1;
}
Rather than the posted convolutions, you could try something similar to this
Assuming:
Not normal C strings
the string_t instances do not contain enough unused memory to
hold both the strings
string 2 is to be inserted at the offset into string 1
the string_t is defined as:
typedef struct
{
char * pStr;
int strLen;
} string_t;
caveat: not compiled, nor tested
string_t *string_insert(
const string_t * originalStr,
const string_t * strToInsert,
size_t index )
{
string_t *newString = NULL;
if( NULL != (newString = malloc( sizeof( string_t )) ) )
{ // then malloc successful
newString->pStr = NULL;
newString->strLen = 0;
// allocate enough room.
if(NULL != (newString->pStr =
malloc( originalStr->strlen + strToInsert->strlen )
{// then mallooc successful
newString->strLen =
origianlStr->strlen + strToInsert->strLen;
//copy first part of originalStr to newString
for( int i = 0; i < index; i++ )
{
newString->pStr[i] = originalStr->pStr[i];
}
// copy string to insert
for( int j=0; j<strToInsert->strlen; j++ )
{
newStr->pStr[i+j] = strToInsert-pStr[j];
}
// copy last part of originalStr to newStr
for ( int k = 0; k<newString->strLen; k++ )
{
newStr->pStr[i+j+k] = origianalStr->pStr[index+k];
}
}
else
{
free( newString );
newString = NULL;
}
}
return newString
} // end function: string_insert
You have
if (str->len < index){
, but you fail to assign anything to str->len.
I'm observing some really weird behavior regarding realloc .... I was wondering if y'all could help me.
I have an array of dynamically allocated char *'s called "frags". I also have a char * called "combination" which points to some string literal that represents a new fragment. I want to replace one of the fragments within "frags" with the contents of "combination." The way my project is structured, I am sending the frags array, index of to-be-replaced frag, and combination string into a function. Within this function I have:
printf("combination before realloc: %s\n", combination);
char *newString = (char *) realloc(frags[firstIndex], strlen(combination) + 1);
assert(newString != NULL);
printf("combination after realloc: %s\n", combination);
strcpy(newString, combination);
frags[firstIndex] = newString;
Oddly, the printf's do not print the same thing. The first printf yields "hellol" which is correct, but the next printf yields jibberish - something like "{?`?p??". Thus, the problem resides in the call to realloc. And I honestly have no idea what's going on. It seems the very call to realloc has messed with combination somehow, but I thought that if that could possibly happen then it would return NULL?
Please help me :(
Edit: Adding code
bool findMaxOverlap(char *first, char *second, char **combination, int *roundMax) {
// setup lng and shrt
char *lng, *shrt;
if (strlen(first) >= strlen(second)) { lng = first; shrt = second; }
else { lng = second; shrt = first; }
int shrtLen = strlen(shrt), lngLen = strlen(lng);
// check if lng contains shrt
if (strstr(lng, shrt) != NULL && shrtLen > *roundMax) {
*combination = lng;
*roundMax = shrtLen;
return true;
}
else // check if lng's tail ends contain part of shrt
{
int numChars = shrtLen - 1, max = 0, shrtOffset = 0, lngOffset = 0;
for (int i = 0; i < shrtLen && numChars > *roundMax && numChars > max; i++) {
numChars = shrtLen - 1 - i;
for (int j = 0; j < lngLen; j++) {
if (strncmp(shrt + i, lng + j, numChars) == 0) {
max = numChars;
shrtOffset = i;
lngOffset = j;
}
}
}
if (shrtOffset > lngOffset) {
// short first
char newFrag[lngLen + shrtOffset + 1];
strncpy(newFrag, shrt, shrtOffset);
strcat(newFrag, lng + shrtOffset);
*combination = newFrag;
*roundMax = numChars;
return true;
} else {
// lng first
char newFrag[lngLen + (shrtLen - numChars) + 1];
strcpy(newFrag, lng);
strcat(newFrag, shrt + numChars);
*combination = newFrag;
printf("combination in findmax is: %s\n", *combination);
*roundMax = numChars;
return true;
}
}
return false;
}
void mergeFrags(char *frags[], int index1, int index2, char *combination) {
int firstIndex, secondIndex;
if (index1 < index2) {
firstIndex = index1;
secondIndex = index2;
} else {
firstIndex = index2;
secondIndex = index1;
}
char temp[strlen(combination) + 1];
strcpy(temp, combination);
char *newString = (char *) realloc(frags[firstIndex], strlen(combination) + 1);
assert(newString != NULL);
strcpy(newString, temp);
frags[firstIndex] = newString;
free(frags[secondIndex]);
}
char *reassemble(char *frags[], int numFrags) {
if (numFrags > 1) {
char *combination;
int max, index1, index2, currNumFrags = numFrags;
for (int currentRound = 0; currentRound < numFrags - 1; currentRound++) {
max = index1 = index2 = 0, combination = NULL;
for (int i = 0; i < currNumFrags; i++) {
for (int j = i+1; j < currNumFrags; j++) {
//find max overlap of pair
if (findMaxOverlap(frags[i], frags[j], &combination, &max)) {
printf("round #: %d, combination: %s, max: %d\n", currentRound, combination, max);
index1 = i; index2 = j;
}
}
}
// merge
mergeFrags(frags, index1, index2, combination);
currNumFrags--;
}
}
return frags[0];
}
You said (in the comments above) that you were using strdup to allocate the data in combination, but what you're really doing is setting combination to point to data that's on the stack. After findMaxOverlap returns, you are now pointing at unallocated space on the stack, and this provides you with the undefined behavior you're seeing. When realloc is called, the area in the stack is reused, and the value of combination looks like garbage.
The exercise it to take an array of strings and, using pointers, concatenate them in a new string. I made it work by hard coding the values at each string array index, but I can't figure out how to make it work if the array has NO elements. I think I need to entirely restructure my code...
#include <stdio.h>
#include <stdlib.h>
int main(int argc, const char * argv[]) {
char *newArray[3];
//original code didn't have newArray as a pointer, and had the following:
//char *firstString = &newArray[0]; This was pointing to the value at the address of newArray[0] which was null at this point in time
//firstString = "Knicks"; This was reassigning the value of firstString to "Knicks" instead of pointing to the value located at the proper index address.
//this code correctly assigns values to each index of the array (which itself is just a pointer that is pointing to these values
newArray[0] = "Knicks";
newArray[1] = "Warriors";
newArray[2] = "Bulls";
//this code correctly assigns pointers that point to the index values of the array, which are all stated above.
char *firstString = newArray[0];
char *secondString = newArray[1];
char *thirdString = newArray[2];
int firstStringCount = 0;
int secondStringCount = 0;
int thirdStringCount = 0;
//count length of first element
for (int i = 0; i < 1000; i++) {
if (firstString[i] == '\0') {
break;
}
else {
firstStringCount++;
}
}
//count length of second element
for (int i = 0; i < 1000; i++) {
if (secondString[i] == '\0') {
break;
}
else {
secondStringCount++;
}
}
//count length of third element
for (int i = 0; i < 1000; i++) {
if (thirdString[i] == '\0') {
break;
}
else {
thirdStringCount++;
}
}
//int len = firstStringCount + secondStringCount + thirdStringCount;
char *concatenatedString = malloc(firstStringCount + secondStringCount + thirdStringCount);
for (int i = 0; i < firstStringCount; i++) {
concatenatedString[i] = firstString[i];
}
for (int i = 0; i < secondStringCount; i++) {
concatenatedString[i+firstStringCount] = secondString[i];
}
for (int i = 0; i < thirdStringCount; i++) {
concatenatedString[i+firstStringCount+secondStringCount] = thirdString[i];
}
//add in null value
concatenatedString[firstStringCount + secondStringCount + thirdStringCount] = '\0';
printf("%s\n", concatenatedString);
printf("%i\n", firstStringCount);
printf("%i\n", secondStringCount);
printf("%i\n", thirdStringCount);
return 0;
}
Your program will work when you have empty strings. This is not the same as having no array elements, because there must still be a \0 terminator in each, such as would be created with
newArray[0] = "";
But you have not allocated enough memory for the destination's string terminator. By using a 1 +
char *concatenatedString = malloc(1 + firstStringCount + secondStringCount +
thirdStringCount);
you now have room for the terminator with
concatenatedString[firstStringCount + secondStringCount + thirdStringCount] = '\0';