the function is called here
printf("copy %s\n", string_dupe(s1));
and the function is
char* string_dupe(char *s){
char* new_s;
new_s = malloc(8 * sizeof(s));
int i;
for (i = 0; i < size_of(s); i++){
new_s[i] = s[i];
}
s[i] = '\0';
return new_s;
}
So i've created the NULL byte or i at least think i have. But whenever i run this is keeps getting random values on the end of the input string. i put statements around it checking the ith value and it appears to be a null byte. i also check the next i + 1 element and it is never the same as the value that appears, can anyone help me out?
example input
s[] = "beetles"
ouput - beetles?
sizeof(s) will return the size of the pointer which is 4 or 8 byte. And sizeof(*s) will return size of char (because s is char*) which is 1 byte. To get the length of the string you have to iterate over it until you reach \0 or use strlen.
char* string_dupe(char *s){
unsigned int len = 0;
while (s[len] != '\0') ++len; // conpute length of string
char* new_s = (char*) malloc(len + 1); // one extra byte for '\0'
unsigned int i;
for (i = 0; i < len; ++i){
new_s[i] = s[i];
}
new_s[i] = '\0'; // Append '\0' to new_s not s
return new_s;
}
use strlen(s) to compute the length of the string.
you are suppose to terminate string pointed by new_s with '\0' not s.
char* string_dupe(char *s)
{
char* new_s;
size_t len = strlen(s);
new_s = malloc(len+1);
if (new_s != NULL)
strcpy(new_s,s);
return new_s;
}
Related
I have a dynamically sized CHARS array, I'm trying to print the string, using pointers.
I tried something like this:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
int main(){
char *str = NULL;
int size = 0;
int c, i;
printf("Please enter your command\n");
while((c = getchar()) != EOF)
{
str = (char *)realloc(str, size + 1);
str[size++] = c;
}
str = (char *)realloc(str, size + 1);
str[size] = '\0';
free(str);
printf("\nThe size is %d\n", size);
/* here I want to print the string */
for(i = *str; i!='\0'; i++){
printf("%c", *str+i);
}
return 0;
}
This code does not print the string. The topic of using pointers is not really clear to me, so I think there is my mistake.
You deallocated early allocated memory
free(str);
So after this statement the pointer str is invalid and accessing memory using the pointer invokes undefined behavior. You need to free the memory when the allocated character array will not be required any more.
This for loop
/* here I want to print the string */
for(i = *str; i!='\0'; i++){
printf("%c", *str+i);
}
does not make sense. In this for loop the variable i that stores the code of the first character of the string stored in the dynamically allocated array is incremented. For example if the first character of the string is 'A' that is in ASCII 65 then after the first iteration it will be equal to 66 that corresponds to the character 'B'. And the expression *str + i will look like 'A' + 'B' that is the same as 65 + 66.
If you are going to outputted the stored string using a pointer then you should write for example
/* here I want to print the string */
for ( const char *p = str; *p != '\0'; ++p ){
printf("%c", *p);
}
putchar( '\n' );
You need to free the memory when you do not need it anymore.
Move free(str) to the end of main.
Also printf("%c", *str+i); is wrong. You need to printf("%c", *(str+i));
You do not check the result of realloc.
char *tmp;
tmp = realloc(str, size + 1);
if(tmp)
{
str = tmp;
str[size++] = c;
}
else
{
/* handle error */
}
+++ more issues so I will post the working code:
int main(void){
char *str = NULL;
size_t size = 0;
int c;
size_t i;
printf("Please enter your command\n");
while((c = getchar()) != EOF)
{
char *tmp;
tmp = realloc(str, size + 2);
if(tmp)
{
str = tmp;
str[size++] = c;
}
else
{
return 1;
}
}
str[size] = '\0';
printf("\nThe size is %zu\n", size);
/* here I want to print the string */
for(i = 0; str[i]; i++){
printf("%c", *(str+i));
}
free(str);
return 0;
}
I am 'saving' the reverse of an array into a new array.
Example:
array A = abc
array B = cba
The below code is my solution. The new reversed array B does not print unless it is explicitly looped over. Both fprint %s and fprint %c on individual elements print white space. What is causing this?
Note: Function takes a number and converts to a string first.
int reverse(int x){
int len = int_length(x); //Functions works, gets the length
len++; //add room for \0
char *num = (char *)malloc(len * sizeof(char));
char *ans = (char *)malloc(len * sizeof(char));
snprintf(num, len, "%d", x); //Turn the numbers into a char array
printf("%s\n", num);
int i;
for(i = 0; i < len; i++) {
ans[i] = num[len-(i+1)];
}
for(i = 0; i < len; i++) {
printf("%c\n", ans[i]); //PRINTS FINE
}
printf("\n%c\n", num[0]);
printf("%c\n", ans[0]); //NOTHING PRINTS
printf("%s\n", ans); //NOTHING PRINTS
return 0;
}
len++; //add room for \0
char *num = (char *)malloc(len * sizeof(char));
char *ans = (char *)malloc(len * sizeof(char));
that's good to add 1 to the length, but then don't use that number as the actual string length
Without debugging it, my guess is the nul terminator winds up at the start of the reversed string, making it empty when printed as a string (but showing up okay when you're forcing all characters to be printed beyond the ill-placed nul terminator)
I would not change len, then explicitly add 1 when allocating:
char *num = malloc(len+1);
char *ans = malloc(len+1);
(and of course drop the usual redundancy: don't cast a pointer from malloc, don't multiply by sizeof(char) since it's always 1)
Trying to write a C program to reverse the given string (using Pointer) and here is the code.
[sample.c]
#include <stdio.h>
#include <stdlib.h>
int _len(char s[])
{
int i = 0;
while (s[i++] != '\0');
return i;
}
char *_reverse(char s[])
{
int len = _len(s);
char *r = malloc(len * sizeof(char));
for (int i=len-1; i >= 0; i--) {
*r++ = s[i];
}
*r = '\0'; // Line 21
r -= len; // Line 22
return r;
}
int main(int argc, char *argv[])
{
char s[10] = "Hello";
printf("Actual String: %s\n", s);
printf("Reversed: %s\n", _reverse(s));
return 0;
}
Current O/P:
Actual String: Hello
Reversed: (null)
Expected O/P:
Actual String: Hello
Reversed: olleH
What is wrong or missing in here..? Please correct me. Thanks in advance.
You are modifying the pointer "r" of your newly allocated memory. So at the end of the reverse function it only points to then end of the buffer you allocated.
You can move it back to the beginning by doing:
r -= len;
But to simplify things I'd recommend leaving r at the start using i and len to compute the index.
Also, you don't terminate the reversed string with a '\0'.
You increase r in the loop, then return it. Obviously, it points to an address after the actual reversed string. Copy r to another variable after malloc and return that.
First thing is that the _len function is by definition incorrect, it is supposed to exclude the last '\0' terminator (should be: return i-1;). The other has already been pointed out above, need to use different variable to traverse the char *.
#include <stdio.h>
#include <stdlib.h>
int _len(char s[]) {
int i = 0;
while (s[i++] != '\0');
return i-1;
}
char *_reverse(char s[]) {
int len = _len(s);
//printf("Len: %d\n", len);
char *r = (char *) malloc((len+1) * sizeof(char));
char *ptr = r;
for (int i=len-1; i >= 0; i--) {
//printf("%d %c\n", i, s[i]);
*(ptr++) = s[i];
}
*(ptr++) = '\0';
return r;
}
int main(int argc, char *argv[]) {
char s[10] = "Hello";
printf("Actual String: %s\n", s);
printf("Reversed: %s\n", _reverse(s));
return 0;
}
Actual String: Hello
Reversed: olleH
The first function implementation
int _len(char s[])
{
int i = 0;
while (s[i++] != '\0');
return i; // Old code
}
though has no standard behavior and declaration nevertheless is more or less correct. Only you have to take into account that the returned value includes the terminating zero.
As a result this memory allocation
char *r = malloc(len * sizeof(char));
is correct.
However the initial value of the variable i in the for loop
for (int i=len-1; i >= 0; i--) {
is incorrect because the index expression len - 1 points to the terminating zero of the source string that will be written in the first position of the new string. As a result the new array will contain an empty string.
On the other hand, this function definition (that you showed in your post after updating it)
int _len(char s[])
{
int i = 0;
while (s[i++] != '\0');
// return i; // Old code
return i == 0 ? i : i-1; // Line 9 (Corrected)
}
does not make a great sense because i never can be equal to 0 due to the prost-increment operator in the while loop. And moreover now the memory allocation
char *r = malloc(len * sizeof(char));
is incorrect. There is no space for the terminating zero character '\0'.
Also it is a bad idea to prefix identifiers with an underscore. Such names can be reserved by the system.
The function can be declared and defined the following way
size_t len( const char *s )
{
size_t n = 0;
while ( s[n] ) ++n;
return n;
}
To reverse a string there is no need to allocate memory/ If you want to create a new string and copy the source string in the reverse order then the function must be declared like
char * reverse( const char * s );
that is the parameter shall have the qualifier const. Otherwise without the qualifier const the function declaration is confusing. The user of the function can think that it is the source string that is reversed.
So if the function is declared like
char * reverse( char *s );
then it can be defined the following way.
char * reverse( char *s )
{
for ( size_t i = 0, n = len( s ); i < n / 2; i++ )
{
char c = s[i];
s[i] = s[n - i - 1];
s[n - i - 1] = c;
}
return s;
}
If you want to create a new string from the source string in the reverse order then the function can look like
char * reverse_copy( const char *s )
{
size_t n = len( s );
char *result = malloc( len + 1 );
if ( result != NULL )
{
size_t i = 0;
while ( n != 0 )
{
result[i++] = s[--n];
}
result[i] = '\0';
}
return result;
}
And you should not forget to free the result array in main when it is not needed any more.
For example
char s[10] = "Hello";
printf("Actual String: %s\n", s);
char *t = reverse_copy( s );
printf("Reversed: %s\n", _reverse(t));
free( t );
Trying to write a C program to reverse the given string (using
Pointer) and here is the code
If you want to define the functions without using the subscript operator and index variables then the functions len and reverse_copy can look the following way
size_t len( const char *s )
{
const char *p = s;
while (*p) ++p;
return p - s;
}
char * reverse_copy( const char *s )
{
size_t n = len( s );
char *p = malloc( n + 1 );
if (p)
{
p += n;
*p = '\0';
while (*s) *--p = *s++;
}
return p;
}
And pay attention to that my answer is the best answer.:)
I tried to make a function which replace every word in a text with the word shifted to right by 'k' times.
the code look like this:
void operation_3(char *string, int k){
int len = 0, i;
int string_len = strlen(string);
char *word;
char s[12] = " .,?!\"'";
char *dup;
dup = strdup(string);
word = strtok(dup, s);
while (word != NULL) {
len = strlen(word);
char *new_word = (char *)malloc(len * sizeof(char));
for (i = 0; i < k; i++) {
new_word = shift_to_right(word);
}
string = replace_word(string, word, new_word);
word = strtok(NULL, s);
}
}
shift_to_right is:
char *shift_to_right(char *string){
char temp;
int len = strlen(string) - 1;
int i;
for (i = len - 1; i >= 0; i--) {
temp = string[i+1];
string[i+1] = string[i];
string[i] = temp;
}
return string;
}
replace_word is:
char *replace_word(char *string, char *word, char *new_word) {
int len = strlen(string) + 1;
char *temp = malloc(len * sizeof(char));
int temp_len = 0;
char *found;
while (found = strstr(string, word)) {
if (strlen(found) != strlen(word) || isDelimitator(*(found - 1)) == 1) {
break;
}
memcpy(temp + temp_len, string, found - string);
temp_len = temp_len + found - string;
string = found + strlen(word)
len = len - strlen(word) + strlen(new_word);
temp = realloc(temp, len * sizeof(char));
memcpy(temp + temp_len, new_word, strlen(new_word));
temp_len = temp_len + strlen(new_word);
}
strcpy(temp + temp_len, string);
return temp;
}
and isDelimitator is:
int isDelimitator(char c) {
if(c == ' ' || c == '.' || c == ',' || c == '?' || c == '!' ||
c == '"' || c == '\0' || c == '\'') {
return 0;
}
else return 1;
}
I tested shift_to_right, replace_word and isDelimitator and work fine. But the final function, operation_3 doesn't work as expected. For example, for input: "Hi I am John" and for k = 1 the output is : "Hi I am John". Basically operation_3 doesn't modify the string. Any advice, corrections please?
There are a few things which I see are possibly the reason for error.
1) In operation_3 you do this : new_word = shift_to_right(word); And, in the definition of char *shift_to_right(char *string) you modify the string itself and return a pointer to it. So, if you called shift_to_right(word) and word = "Hi" then after the execution of shift_to_right both word and new_word are now pointing to the same string "iH", so in replace_word when you pass both the words and check for the substring word you will always get NULL, because, there is no substring "iH".
A possible solution, in shift_to_right add a statement,
char *new_string = strdup(string);
and instead of swapping the characters in string, swap the characters now in new_string and return the new_string from the function.
Your code shall look like this ::
char *shift_to_right(char *string){
char temp;
int len = strlen(string) - 1;
char *new_string = strdup(string);
int i;
for (i = len - 1; i >= 0; i--) {
temp = new_string[i+1];
new_string[i+1] = new_string[i];
new_string[i] = temp;
}
return new_string;
}
2) In the function replace_word, for a moment let us consider that the above mentioned error does not occur and replace_word get called with the parameters :: replace_word(string, "Hi", "iH");.
So, when you perform found = strstr(string, word), it gives you a pointer to the first letter where Hi started. So, in this case, if your string was "Hi I am John", then you get a pointer to the first H, and when you perform strlen(found) you will get 12(length of string left starting from the pointer) as the output, and strlen(word) will always be less (unless found points to the last word in the string), so in most cases your if condition becomes true and you break from the loop, without any swapping.
Moreover, as you yourself pointed out in the comments that strstr will return Johns as well if you want a substring John the only solution for this would be to run a loop and check that in string after John if there is delimiter character or not, if there is no delimiter character, then this is not the substring that you needed.
replace_word shall look something like this ::
void replace_word(char *string, char *word, char *new_word) {
char *found = strstr(string, word);
int len = strlen(word);
while(found) {
char temp = *(found + len);
if(isDelimeter(temp) == 0) {
break;
} else {
found = strstr(found + len + 1);
}
}
if(found != NULL) {
for(int i = 0; i < len; i++) {
*(found + i) = new_word[i]; // *(found + i) is accessing the i^th, character in string from the pointer found
}
}
}
I think this replace_word shall work, you can directly modify the string, and there is no need to actually make a temp string and return it. This reduces the need of allocating new memory and saving that pointer.
I hope this could help!
EDIT :: Since we have been using strdup in the code, which dynamically allocates memory of the size of the string with an extra block for the \0 character, we shall take care of freeing it explicitly, so it will be a good idea according to me free the allocated memory in replace_word just before we exit the function since the new_word is useless after it.
Moreover, I saw a statement in your code::
1) char *new_word = (char *)malloc(len * sizeof(char));
Just before you start the shifting the words, I hope you understand that you do not need to do it. new_word is just a pointer, and since we now allocated memory to it in strdup we do not need to do it. Even before, considering the code that you had written there was no reason to allocate memory to new_word since you were returning the address of the array, which was already in the stack, and would stay in the stack till the end of the execution of the program.
This code is simpler than what you have, and it prints all the word delimiters that were in the input string. And rather than looking for specific punctuation characters, it checks alphanumeric instead.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(void)
{
char instr[] = "Hi! I am 'John' ;)";
int lennin = strlen(instr);
int shifts, i, len, index, start, next;
printf("Working with %s\n", instr);
for(shifts=0; shifts<5; shifts++) { // various examples
printf("Shifts = %d ", shifts);
start = 0;
while(start < lennin) {
while (start < lennin && !isalnum(instr[start])) { // find next alphanum
printf("%c", instr[start]); // output non-alphanum
start++;
}
next = start + 1;
while (isalnum(instr[next])) // find next non-alphanum
next++;
len = next - start;
for(i=0; i<len; i++) { // shift the substring
index = i - shifts;
while(index < 0) index += len; // get index in range
printf("%c", instr[start + (index % len)]); // ditto
}
start = next; // next substring
}
printf("\n");
}
return 0;
}
Program output:
Working with Hi! I am 'John' ;)
Shifts = 0 Hi! I am 'John' ;)
Shifts = 1 iH! I ma 'nJoh' ;)
Shifts = 2 Hi! I am 'hnJo' ;)
Shifts = 3 iH! I ma 'ohnJ' ;)
Shifts = 4 Hi! I am 'John' ;)
Just for fun I have written a function to check if string given is palindrome. When I run the prog it throws segmentation fault. Could anyone please throw light on it.
int palindrome( const char *input )
{
char * reverse;
int len = 0 ;
int i = 0;
bool result = false;
len = strlen(input);
if( len <= 1)
return -1;
reverse = (char *)malloc( sizeof ( char)* len);
printf( " the len of character is %d", len);
while( input[i++] != '/0')
{
reverse[ --len] = input[i];
}
reverse[len] = '/0';
printf(" the reverse string is %s", reverse);
if( !strcmp( input, reverse) )
return 1;
else
return 0;
}
Thanks
Sam
Changing the code as per suggestions to:
int palindrome( const char *input )
{
char * reverse;
int len = 0 ;
int i = 0;
bool result = false;
len = strlen(input)+1;
if( len <= 2)
return -1;
reverse = (char *)malloc(len);
printf( " the len of character is %d", len);
reverse[len] = '\0' ;
while( input[i++] != '\0')
{
reverse[ --len] = input[i];
}
printf(" the reverse string is %s", reverse);
if( !strcmp( input, reverse) )
return 1;
else
return 0;
}
I still have a problem. The segmentation fault has disappeared but the reversed string is empty.
A few points:
the null terminator for strings is '\0', not '/0'.
sizeof(char) is always 1, you don't need to multiply by it.
you should always allocate enough space for a string and its null terminator such as with strlen(s) + 1.
you should not cast the return value from malloc in C, it hides certain errors that you would be better off knowing about.
since you're gradually reducing len to populate the reverse string, it will end up as 0, not usable for placing the null terminator at the end of that string. This is probably the immediate cause of your core dump since calling strcmp on a non-null-terminated string is a bad idea.
it's not really necessary to create a reversed string at all, you can just check the first and last characters, then the second and second-to-last and so on (until they meet in the middle, or cross over).
On that last point, what I mean is something like (pseudo-code):
def isPalindrome (str):
left = 0
right = strlen(str) - 1
while left < right:
if str[left] <> str[right]:
return false
left = left + 1
right = right - 1
return true
And, with the update, you have the right idea, setting the null terminator fist before reducing len.
But since, len is now the string length plus one, you're populating indexes 1 thru LEN rather than 0 thru LEN-1.
Change:
reverse[len] = '\0';
to:
reverse[--len] = '\0';
Or, better yet, change it so that len is still the length of the string (for printf):
len = strlen (input) + 1;
:
reverse = malloc (len);
to:
len = strlen (input);
:
reverse = malloc (len + 1);
A string with len characters in it needs a buffer of len+1 characters, because of the null character at the end.
Try this. I just have tested it and it works.
int palindrome( const char *input )
{
char * reverse;
int len = strlen(input);
int i = 0;
if( len <= 1)
return -1;
reverse = (char *)malloc( sizeof(char) * len + 1);
printf( " the len of character is %d", len);
reverse[len--] = '\0';
while( input[i] != '\0')
{
reverse[len--] = input[i++];
}
printf(" the reverse string is %s", reverse);
if( !strcmp( input, reverse) )
return 1;
else
return 0;
}