I have the following code that prints as intended in ubuntu linux but prints nothing in cygwin in windows. However, if I get rid of free(t) in is_rotation function then it works ok. I want to know if I am doing bad memory management or it is a cygwin issue. Why it is happening. And any other suggestion to improve the memory management.
Here is the code:
/**
* sub is a substring of str or not
**/
int is_substring(const char* str,const char* sub){
const char* s1=str;
const char* s2=sub;
int count=0;
while(1){
if(*s2=='\0') return 1;
else if(*s1=='\0') return 0;
else if(*s1==*s2){
count++;
s2++;
}
else{
if(count!=0){
s1-=count;
count=0;
s2=sub;
}
}
s1++;
}
return 0;
}
/**
* s1 and s2 are rotations of eachother or not, given only the is_substring function.
**/
int is_rotation(const char* s1,const char* s2){
int l1=strlen(s1);
if(l1!=strlen(s2)) return 0;
char* t=malloc(2*l1*sizeof(char));
strcat(t,s1);
strcat(t,s1);
int r=is_substring(t,s2);
free(t);
return r;
}
/**
* USAGE: ./a.out string1 string2
**/
int main(int argc, char *argv[]){
if(argc<3) return 1;
printf("is_substring=%d",is_substring(argv[1],argv[2]));
printf("\nis_rotation=%d",is_rotation(argv[1],argv[2]));
return 0;
}
Thanks for the help :)
The issue is in the first strcat() call. You should replace it with a strcpy() instead.
int is_rotation(const char* s1,const char* s2){
int l1=strlen(s1);
if(l1!=strlen(s2)) return 0;
char* t=malloc(2*l1*sizeof(char) + 1);
strcpy(t,s1); // initialize with strcpy() so we have a null in the string
strcat(t,s1);
int r=is_substring(t,s2);
free(t);
return r;
}
Note that malloc() does not initialize the buffer it allocates normally. Perhaps the one on ubuntu does, but it is not guaranteed. In cygwin, the buffer is not initialized, so the strcat() is walking memory looking for a null before it copies the string... which very likely is past the end of your allocated buffer.
Also, you have to add an extra character to the buffer to hold the null terminator for the final string... it's 2x the length of l1 + 1 for the null terminator
Here is a bug that kills your stack:
char* t=malloc(2*l1*sizeof(char));
strcat(t,s1);
strcat(t,s1);
The first strcat adds characters to somewhere... As you are using malloc the contents of the t buffer is unknown. Also you need one more byte for zero.
char* t=malloc(2*l1+1); // (2*l1+1)*sizeof(char)
strcpy(t,s1);
strcat(t,s1);
Related
How can I implement a function that will concatenate something to a char* (not char array)?
Example of what I want:
#include <stdio.h>
#include <string.h>
int main() {
char* current_line;
char temp[1];
sprintf(temp, "%c", 'A');
// This causes a seg fault. I of course don't want that, so how do I get this to work properly?
strcat(current_line, temp);
return 0;
}
How can I fix this to work properly (and please, tell me if I need to add anything to my question or point me in the right direction because I couldn't find anything)?
Edit: I made this but it seg faults
char* charpointercat(char* mystr, char* toconcat) {
char ret[strlen(mystr) + 1];
for(int i = 0; mystr[i] != '\0'; i++) {
ret[i] = mystr[i];
}
return ret;
}
You have 3 problems:
You do not allocate memory for current_line at all!
You do not allocate enough memory for temp.
You return a pointer to a local variable from charpointercat.
The first one should be obvious, and was explained in comments:
char *current_line only holds a pointer to some bytes, but you need to allocate actual bytes if you want to store something with a function like stracat.
For the secoond one, note that sprintf(temp, "%c", 'A'); needs at least char temp[2] as it will use one byte for the "A", and one byte for terminating null character.
Since sprintf does not know how big temp is, it writes beyond it and that is how you get the segfault.
As for your charpointercat once the function exits, ret no longer exists.
To be more precise:
An array in C is represented by a pointer (a memory address) of its first item (cell).
So, the line return ret; does not return a copy of all the bytes in ret but only a pointer to the first byte.
But that memory address is only valid inside charpointercat function.
Once you try to use it outside, it is "undefined behavior", so anything can happen, including segfault.
There are two ways to fix this:
Learn how to use malloc and allocate memory on the heap.
Pass in a third array to the function so it can store the result there (same way you do with sprintf).
From the first code you posted it seems like you want to concatenate a char to the end of a string... This code will return a new string that consists of the first one followed by the second, it wont change the parameter.
char* charpointercat(char* mystr, char toconcat) {
char *ret = (char*) malloc(sizeof(char)*(strlen(mystr) + 2));
int i;
for(i = 0; mystr[i] != '\0'; i++) {
ret[i] = mystr[i];
}
ret[i] = toconcat;
ret[i + 1] = '\0';
return ret;
}
This should work:
char* charpointercat(char* mystr, char* toconcat) {
size_t l1,l2;
//Get lengths of strings
l1=strlen(mystr);
l2=strlen(toconcat);
//Allocate enough memory for both
char * ret=malloc(l1+l2+1);
strcpy(ret,mystr);
strcat(ret,toconcat);
//Add null terminator
ret[l1+l2]='\0';
return ret;
}
int main(){
char * p=charpointercat("Hello","World");
printf("%s",p);
//Free the memory
free(p);
}
I have Wrote the Following Code Snippet but it is not working.
Can anyone help me? Where i am Wrong ??
char *xstrrev(char *string)
{
int len=0,i=0;
char *reverse;
while(*string!='\0')
{
len++;
string++;
}
len=len-1;
while(len>=0)
{
*reverse=string[len];
reverse++;
len--;
}
*reverse='\0';
return reverse;
}
int main()
{
char name[10];
scanf("%s",name);
printf("%s",xstrrev(name));
return 0;
}
I am unable to return whole string in the main function
The problem starts (and ends) with
*reverse=string[len];
where reverse is not initialized. This invokes undefined behavior.
You need to initialize reverse to make it point to a valid memory location before you can dereference the pointer.
Since you are expecting to _return_ the new _string_ from your function and use it in the caller, you should use memory allocator functions, like malloc() to allocate memory and initialize the reverse with the returned pointer, after the success check of the malloc() call. You also need to take care of free()-ing the allocated memory , once you're done using it.
After that, as per your logic, you're doing reverse++; and in the end, you're returning reverse, so think of the exact value which is getting returned. You're returning a pointer to the end of the string, not a pointer to the start of it. You need to keep a copy of the actual start of reverse and return that.
Three problems:
[1] reverse not pointing to valid memory area.
[2] returning reverse will return the last byte address of string reverse. so need to store the start of reverse and return the start of reverse.
[3] string is completely parsed while calculating the length, so again, start of original string needs to be saved and used subsequently
char *xstrrev(char *string)
{
char *original_string = string;
int len=0,i=0;
//[1] char *reverse;
while(*string!='\0')
{
len++;
string++;
}
//[3] till here "string" is completely parsed, so it points to past the end.
char *reverse = (char*)malloc(len + 1);
char *reverse_to_be_returned = reverse;
len=len-1;
while(len>=0)
{
//[3] *reverse=string[len];
*reverse = original_string[len];
reverse++;
len--;
}
*reverse='\0';
//[2] return reverse;
return reverse_to_be_returned;
}
You need to allocate space for char *reverse to point to. This can be done with malloc or strdup.
Basically:
malloc()allocates requested memory on the heap, and returns a void* pointer in the end.
You also need to check the return pointer of any call to malloc(), as sometimes it can return NULL if something wrong happens.
You also need to free this requested memory at the end, just to be safe.
Additionally, since you are returning a pointer, you need to make sure it points at the start of the string, instead of the end.
Your code can look like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NAMESTRLEN 10
char *xstrrev(char *string);
int
main(void) {
char name[NAMESTRLEN+1];
char *result;
printf("Enter string: ");
scanf("%10s", name);
result = xstrrev(name);
printf("Reversed string = %s\n", result);
free(result);
return 0;
}
char
*xstrrev(char *string) {
char *result;
size_t slen, count = 0;
int i;
slen = strlen(string);
result = malloc(slen+1); /* +1 for nullbyte */
if (!result) {
printf("Cannot allocate space for string.\n");
exit(EXIT_FAILURE);
}
for (i = slen-1; i >= 0; i--) {
result[count++] = string[i];
}
result[count] = '\0';
return result;
}
So i'm trying to create a simple String struct which will contain the text of the string and the size of it, at least for now. However I'm having issues allocating my struct. Right now i'm simply trying to get a size of 1 character to work, but its simply crashing at this point and i don't know what i'm doing wrong with the allocation, please help.
#include <stdio.h>
#include <stdlib.h>
typedef struct{
char* text;
int size;
}String;
String* getString();
int main(int argc, char** argv){
String* str1 = getString();
printf("%s",str1->text);
free(str1);
return 0;
}
String* getString(){
String* str = (String*)malloc(sizeof(String));
scanf("%s",str->text);
str->size++;
return str;
}
You need to allocate memory for the structure but also for text string.
scanf("%s",str->text);
str->text is an uninitialized pointer.
You don't allocate any memory for str->text. You leave it uninitialized, so your program invokes undefined behavior.
You need to allocate memory for it using str->text = malloc(MAX_SIZE); where MAX_SIZE is the maximal size for the string. Alternatively, if your strings will be short, you may use a regular, fixed-szie array instead.
Furthermore, you probably do not want to use scanf() for scanning strings. One particular reason is that %s makes scanf() stop at the first whitespace character. Another reason is that it's not trivial to prevent scanf() from writing past the buffer if it's too small.. How about using fgets() instead?
fgets(str->text, MAX_SIZE, stdin);
is a better and safer approach.
int main(int argc, char** argv){
String* str1 = getString();
printf("%s",str1->text);
free(str1->text);
free(str1);
return 0;
}
String* getString(){
String* str = (String*)malloc(sizeof(String));//for struct
str->size = 16;//initialize
str->text = (char*)malloc(sizeof(char)*str->size);//for input text
int ch, len;
while(EOF!=(ch=fgetc(stdin)) && ch != '\n'){
str->text[len++]=ch;
if(str->size==len){
str->text = realloc(str->text, sizeof(char)*(len+=16));
}
}
str->text[len++]='\0';
str->text = realloc(str->text, sizeof(char)*(str->size=len));
return str;
}
I wrote a substr function in c, I can get the returned value inside the substr function, but can not get the returned value in main function. Below is all the code:
#include <stdio.h>
#include <string.h>
char* substr(char *source, int start, int length)
{
char result[10];
char *r = result;
strncpy(result, source+start, length);
printf("substr: %s\n", r);
return r;
}
int main()
{
printf("main: %s\n", substr("HELLO", 1, 2));
}
and the output is:
substr: EL
main:
I'm not familiar with c, anybody get the idea to fix this, thanks in advance.
result only exists during the call to your substr.
Your main is referencing bad memory.
you could fix it by:
making result static in substr.
dynamically allocating result (remember to free)
making result global
As cthulhu ( "Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn" ) points out: even if you applied one of my fixes: your string isn't nul terminated.
Also since you have a fixed size result buffer, you could cause problems by asking for a substring longer than 10 - either check your arguments, or don't use a fixed size buffer.
I haven't tested this, so there may well be an "off by one" problem or two lurking in the corners...
/*
* Caller must free the results if they are non null
*/
char* substr(char *source, int start, int length)
{
/* If the input is NULL, return NULL */
if (source == NULL) return NULL;
int len = strlen(source);
/* If the requested start is off the end of the string, return NULL */
if (start > len) return NULL;
/* If the requested length is 0 or less, return NULL */
if (length <= 0) return 0;
char *r = (char*)malloc(length + 1); /* allow space for null terminator */
if (r != NULL) {
int i = 0;
while(source[start] != '\0' && i < length) {
r[i++] = source[start++];
}
r[i] = '\0';
printf("substr: %s\n", r);
}
return r;
}
If you're going to be expecting to return a value to the caller then you should pass the place where the string will be stored to the function. Standard library functions like strcpy do this. Here is a very simple example. It assumes dest is already declared and is big enough to store it.
char * substr(char * dest, char * src, int start, int length)
{
// Move substring into passed destination pointer
strncpy(dest, src + start, length);
// Append null to the end to terminate string
dest[length] = 0;
// Return string pointer that can be used in printf and other places
return dest;
}
int main(int argc, char const *argv[])
{
char * test = "This is a test.";
char * dest = malloc(10);
printf("%s", substr(dest, test, 5, 2));
free(dest);
return 0;
}
Output:
is
Edit: To all the people returning values that are malloc'd inside the function, how do you expect people to free the memory if they just use it in a print statement? They receive no pointer to free and the memory will just be left hanging there.
The below code allocate memory on the heap. Just free your memory when you are done. strlcpy always NUL-terminate its strings as others have pointed out.
#include <string.h>
char *
substr(char *s, int start, int len)
{
char *ss;
if(strlen(s) < start + len)
return NULL;
if((ss = malloc(len + 1)) == NULL)
return NULL;
strlcpy(ss, s + start, len);
return ss;
}
int
main(void)
{
char *s = substr("Hello World!", 6, 5);
printf("%s\n", s);
free(s);
return 0;
}
Should print World.
To use strlcpy in Debian Linux use:
gcc -lcext -o prog prog.c
If your operating system doesn't provide strlcpy just include it yourself in your source. It is licensed under the BSD license, that means free to use, sell, etc, as long you include the license itself.
The implementation of strlcpy can be found on OpenBSD's CVS Web.
Dynamic and Static Variables in C
Variable declarations can be outside all functions or inside a function
Declarations outside all functions are global and in fixed memory locations
The static declaration declares a variable outside a function to be a “file global” (cannot be referenced by code in other source files)
Declarations within a block statement {} (function body or block statement nested within a function body):
Are dynamically allocated, unless declared static
Are allocated memory when program execution enters the block
Memory is released when execution exits the block
If a function calls itself (directly or indirectly), it gets a new set of dynamic variables (called a stack frame)
This is handled no differently from any other call to the function
You have problem, the variable result[] is a variable that has been allocated in side the function — whose lifetime extends across the entire run of the function(allocated at the stack!) because of that you need to make the result Dynamic variable
Fix code:
#include <stdio.h>
#include <string.h>
char* substr(char *source, int start, int length)
{
char* result;
char *r;
result=(char*)malloc(sizeof(char)*10);
r = result;
strncpy(result, source+start, length);
printf("substr: %s\n", r);
return r;
}
int main()
{
char* r=substr("HELLO", 1, 2);
printf("main: %s\n",r );
free(r)//Don't forget to free it!
}
OR you can make result[] global variable like this:
#include <stdio.h>
#include <string.h>
char result[10];//<======Global
char* substr(char *source, int start, int length)
{
char *r=result;
r = result;
strncpy(result, source+start, length);
printf("substr: %s\n", r);
return r;
}
int main()
{
printf("main: %s\n",substr("HELLO", 1, 2));
}
Language: C
I am trying to program a C function which uses the header char *strrev2(const char *string) as part of interview preparation, the closest (working) solution is below, however I would like an implementation which does not include malloc... Is this possible? As it returns a character meaning if I use malloc, a free would have to be used within another function.
char *strrev2(const char *string){
int l=strlen(string);
char *r=malloc(l+1);
for(int j=0;j<l;j++){
r[j] = string[l-j-1];
}
r[l] = '\0';
return r;
}
[EDIT] I have already written implementations using a buffer and without the char. Thanks tho!
No - you need a malloc.
Other options are:
Modify the string in-place, but since you have a const char * and you aren't allowed to change the function signature, this is not possible here.
Add a parameter so that the user provides a buffer into which the result is written, but again this is not possible without changing the signature (or using globals, which is a really bad idea).
You may do it this way and let the caller responsible for freeing the memory. Or you can allow the caller to pass in an allocated char buffer, thus the allocation and the free are all done by caller:
void strrev2(const char *string, char* output)
{
// place the reversed string onto 'output' here
}
For caller:
char buffer[100];
char *input = "Hello World";
strrev2(input, buffer);
// the reversed string now in buffer
You could use a static char[1024]; (1024 is an example size), store all strings used in this buffer and return the memory address which contains each string. The following code snippet may contain bugs but will probably give you the idea.
#include <stdio.h>
#include <string.h>
char* strrev2(const char* str)
{
static char buffer[1024];
static int last_access; //Points to leftmost available byte;
//Check if buffer has enough place to store the new string
if( strlen(str) <= (1024 - last_access) )
{
char* return_address = &(buffer[last_access]);
int i;
//FixMe - Make me faster
for( i = 0; i < strlen(str) ; ++i )
{
buffer[last_access++] = str[strlen(str) - 1 - i];
}
buffer[last_access] = 0;
++last_access;
return return_address;
}else
{
return 0;
}
}
int main()
{
char* test1 = "This is a test String";
char* test2 = "George!";
puts(strrev2(test1));
puts(strrev2(test2));
return 0 ;
}
reverse string in place
char *reverse (char *str)
{
register char c, *begin, *end;
begin = end = str;
while (*end != '\0') end ++;
while (begin < --end)
{
c = *begin;
*begin++ = *end;
*end = c;
}
return str;
}