Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I have a function to replace tabs with spaces in a string that looks like this:
#include <stdio.h>
char *detab(char *string)
{
for (int i = 0; string[i] != '\0'; i++)
if (string[i] == '\t')
string[i] = ' ';
return string;
}
int main(int argc, char **argv)
{
char *string = "\thello\thello";
detab(string);
printf("%s\n", string);
return 0;
}
But when I run it on "\thello\thello\t", it produces a segmentation fault. Why does it do this? I'm pretty new to C, so I may be missing something trivial.
This could be because the calling code did not allocate enough space for the string. It must always allocate at least one space larger than the visible characters in the string to allow space for the \0.
That being said, since strings are mutable, there is no need to return the string. It it will modify the string as you are working.
Here would be a working version of your code:
void detab(char * myStr)
{
for (int i = 0; myStr[i] != '\0'; i++)
if (myStr[i] == '\t')
myStr[i] = ' ';
}
char theString[] = "\thello\thello\t";
printf("Before: %s", theString);
detab(theString);
printf("After: %s", theString);
Also, keep in mind the following:
char buffer[4] = "test"; //THIS IS NOT SAFE. It might work, but it will overwrite stuff it shouldn't
char buffer[5] = "test"; //This is Ok, but could be an issue if you change the length of the string being assigned.
char buffer[] = "test"; //This is preferred for string literals because if you change the size of the literal, it will automatically fit.
UPDATE: Base on the main method you added, here is your issue:
You need to change
char * string = "\thello\thello";
To
char string[] = "\thello\thello";
The reason is because, when you define a string literal and assign it to a char *, it resides in the text portion of memory, and cannot be modified safely. Instead, you should assign the string literal to a char [] (which can be passed as a char * since that is what its actual type is). This syntax will let the compiler know it should allocate space on the stack and populate it with the values in the string literal, allowing it to be modified.
char * joe = "blah" simply creates the char * pointer, and points it to the data in the text portion (which is immutable).
char joe[] = "blah" tells the compiler to create an array of the appropriate length on the stack, to load it with the string literal, to create the char * pointer, and then to point the pointer at the start of the array of data on the stack.
This works:
#include <stdio.h>
#include <string.h>
char *detab(char *string)
{
for (int i = 0; string[i] != '\0'; i++)
if (string[i] == '\t')
string[i] = ' ';
return string;
}
int main ( int argc, char ** argv ) {
char str[21] = "\thello\thello\t";
printf( "%s\n", detab( str ) );
return 0;
}
As others have said, it's probably segfaulting because you're modifying a string literal. With char str[21], the string literal is copied into the stack-allocated str, where it can then be modified by your function.
Are you sure the strings are always null terminated.
Try some belt and braces...
char *detab(char *string)
{
int s_len= strlen(string) + 1;
for (int i = 0; string[i] != '\0'; i++)
{
if (string[i] == '\t')
{ string[i] = ' '; }
if (i == s_len) { /* failure - print some diagnostic */ return NULL; }
}
return string;
}
Related
I'm writing a program to return a the rest of a string after the first white space.
"I had a bad day"
should return
"had a bad day"
This is what I have so far
char* next_word(char* str){
char s[100];
int index = 0;
int i = 0;
int counter = 0;
for(i = 0; i < strlen(str); i++){
if(str[i] == ' '){
index = i+1;
for(index; index < strlen(str); index++){
s[counter] = str[index];
counter = counter + 1;
}
s[index] = '\0';
return s;
}
}
return index;
}
I'm looping through the char* str and finding the index of the first empty space then from there I've made another loop to print out the rest of the string starting at index + 1. For some reason when I writes s[counter] = str[index], I don't believe that its copying the char from str to s.
When I try to return s after the loop I don't get anything. Is it possible to add char to the empty char s[100] then return the full string as s?
Thank You
Your next_word() function is returning a local (to the function) variable which results in a undefined behavior. You must take s (in your case) as input or malloc a character buffer in the function. Then you can do the copying. I prefer you go for the first alternative and do not forget to check the length of the input string, so that you do not cross the size while copying.
Also, the next_word() returns index when no space found? That is clearly a mistake and your code will fail to compile.
For the code, you can just break from the first loop whenever you find the first space and from there you can continue with copying.
You should not return s as it is a local variable on the stack. You could simply return a pointer into the str argument since str remains valid at the time of return.
#include <string.h>
const char* TheString = "I had a bad day";
const char* stringAfterBlank(const char* str)
{
const char* blank = strchr(str, ' ');
if (blank != NULL)
{
return ++blank;
}
return "";
}
void main(int argc, char** argv)
{
const char* restOfTheString = stringAfterBlank(TheString);
// restOfTheString is "had a bad day" pointing into TheString
}
If you need a copy of the string then you can use strdup. If you do then don't forget to free.
You shouldn't return your local variable. The easiest way to accomplish what you want is operating on pointers.
There is solution using only stdio.h, as you wanted:
#include <stdio.h>
char* next_word(char* str);
int main()
{
char* arg = "I had a bad day!";
//Print every "next_word"
char* words = arg;
do{
printf("%s\n", words);
} while(words = next_word(words));
}
char* next_word(char* str)
{
while(*str != '\0'){
if(*str++ == ' ')
return str;
}
return NULL;
}
I am trying to break up the sentence "once upon a time" into an array of words. I am doing this via a for loop, detecting three conditions:
It's the end of the loop (add the \0 and break);
It's the separator character (add the \0 and advance to the next word)
It's anything else (add the character)
Here is what I have now:
#include <stdlib.h>
#include <stdio.h>
char ** split_string(char * string, char sep) {
// Allow single separators only for now
// get length of the split string array
int i, c, array_length = 0;
for (int i=0; (c=string[i]) != 0; i++)
if (c == sep) array_length ++;
// allocate the array
char ** array_of_words = malloc(array_length + 1);
char word[100];
for (int i=0, char_num=0, word_num=0;; i++) {
c = string[i];
// if a newline add the word and break
if (c == '\0') {
word[char_num] = '\0';
array_of_words[word_num] = word;
break;
}
// if the separator, add a NUL, increment the word_num, and reset the character counter
if (c == sep) {
word[char_num] = '\0';
array_of_words[word_num] = word;
word_num ++;
char_num = 0;
}
// otherwise, just add the character in the string and increment the character counter
else {
word[char_num] = c;
char_num ++;
}
}
return array_of_words;
}
int main(int argc, char *argv[]) {
char * input_string = "Once upon a time";
// separate the string into a list of tokens separated by the separator
char ** array_of_words;
array_of_words = split_string(input_string, ' ');
printf("The array of words is: ");
// how to get the size of this array? sizeof(array_of_words) / sizeof(array_of_words[0]) gives 1?!
for (int i=0; i < 4 ;i++)
printf("%s[sep]%d", array_of_words[i], i);
return 0;
}
However, instead of printing "once", "upon", "a", "time" at the end, it's printing "time", "time", "time", "time".
Where is the mistake in my code that is causing this?
Here is a working example of the code: https://onlinegdb.com/S1ss6a4Ur
You need to allocate memory for each word, not just for one. char word[100]; only puts aside memory for one word, and once it goes out of scope, the memory is invalid. Instead, you could allocate the memory dynamically:
char* word = malloc(100);
And then, when you found a separator, allocate memory for a new word:
if (c == sep) {
word[char_num] = '\0';
array_of_words[word_num] = word;
word = malloc(100);
Also, this here is incorrect:
char ** array_of_words = malloc(array_length + 1);
You want enough memory for all the char pointers, but you only allocate 1 byte per pointer. Instead, do this:
char ** array_of_words = malloc(sizeof(char*)*(array_length + 1));
The sizeof(array_of_words) / sizeof(array_of_words[0]) works to calculate the amount of elements when array_of_words is an array, because then its size is known at compile time (barring VLAs). It's just a pointer though, so it doesn't work as sizeof(array_of_words) will give you the pointer size. Instead, you'll have to calculate the size on your own. You already do so in the split_string function, so you just need to get that array_of_words out to the main function. There are multiple ways of doing this:
Have it be a global variable
Pass an int* to the function via which you can write the value to a variable in main (this is sometimes called an "out parameter")
Return it along with the other pointer you're returning by wrapping them up in a struct
Don't pass it at all and recalculate it
The global variable solution is the most simple for this small program, just put the int array_length = 0; before the split_string instead of having it inside it.
Last but not least, since we used malloc to allocate memory, we should free it:
for (int i = 0; i < array_length; i++) {
printf("%s[sep]%d", array_of_words[i], i);
free(array_of_words[i]); // free each word
}
free(array_of_words); // free the array holding the pointers to the words
Is strtok not suitable?
char str[] = "once upon a time";
const char delim[] = " ";
char* word = strtok(str, delim);
while(word != NULL)
{
printf("%s\n", word);
word = strtok(NULL, delim);
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX40 40
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
Int40 *parseString(char *str)
{
Int40 *p;
char *ptr;
int i, len, value, ptrValue;
printf("%s\n", str);
for(i = 0; i < 40; i++)
{
if(str[i] == 'a')
{
printf("%c\n", str[i]);
str[i] = '0';
printf("%c\n", str[i]);
}
}
}
int main(int argc, char *argv[])
{
// char string[40] = "
// char *str = string;
Int40 *p;
parseString("0123456789abcdef0123456789abcdef01234567");
return 0;
}
In my parseString function, between the two printf statements, I'm trying to assign the value at the specific point of 'a' to 0. I'm not sure how I'm supposed to be attempting this, and I would like to keep the variables the same as well.
Your problem here is that you are passing to parseString a pointer to a
string literal. Modifying the contents of string literals is undefined behaviour
and most of the times string literals reside in read only memory, that's why
your program crashes.
You have to create an array and initialize it with the string you want, then
pass that array to the function:
#include <string.h>
void parseString(char *str, size_t len)
{
printf("%s\n", str);
for(size_t i = 0; i < len; i++)
{
if(str[i] == 'a')
{
printf("%c\n", str[i]);
str[i] = '0';
printf("%c\n", str[i]);
}
}
}
int main(int argc, char *argv[])
{
char text[] = "0123456789abcdef0123456789abcdef01234567";
parseString(text, sizeof text / sizeof *text);
return 0;
}
Bear in mind when you pass an array to a function, the function gets only a
pointer to the first element of the array. For that reason the function being
called cannot determine the length of the array. It's better practice to pass
the length of the array as well. That's why I added size_t len as an argument
in parseString. In main where the array is declared, I calculate the
length of the array with sizeof text / size *text. Note that this only works
with pure array, if you did sizeof str / sizeof *str in parseString, you
will definitively get a wrong result, that's why you should always pass the
length of the array.
Your program is having undefined behavior.
As per the standard attempting to modify a string literal results in undefined behavior because they may be stored in read-only storage or combined with other string literals.
You are passing string literal to parseString() function:
parseString("0123456789abcdef0123456789abcdef01234567");
and in parseString(), trying to modify it:
str[i] = '0';
Instead, in main() function you can do:
char str[] = "0123456789abcdef0123456789abcdef01234567";
which is equivalent to:
char str[] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','0','1','2','3','4','5','6','7','\0'};
[Note the terminating null-character at the end.]
So, you can do:
#include <stdio.h>
void parseString(char *pstr)
{
char * str = pstr;
printf("%s\n", str);
for(int i = 0; str[i] != '\0'; i++)
{
if(str[i] == 'a')
{
printf("%c\n", str[i]);
str[i] = '0';
printf("%c\n", str[i]);
}
}
printf("%s\n", pstr);
}
int main(int argc, char *argv[])
{
char str[] = "0123456789abcdef0123456789abcdef01234567";
parseString(str);
printf("%s\n", str);
return 0;
}
Note that in my program, I am only demonstrating the replacement of 'a' with '0' character. Hence, I removed typedef struct Int40... which exists in OP's code.
char * removeChar(char * str, char c){
int len = strlen(str);
int i = 0;
int j = 0;
char * copy = malloc(sizeof(char) * (len + 1));
while(i < len){
if(str[i] != c){
copy[j] = str[i];
j++;
i++;
}else{
i++;
}
}
if(strcmp(copy, str) != 0){
strcpy(str,copy);
}else{
printf("Error");
}
return copy;
}
int main(int argc, char * argv[]){
char str[] = "Input string";
char * input;
input = removeChar(str,'g');
printf("%s\n", input);
free(input);
return 0;
}
I don't know why every time I try to run it ,it always says uninitialized variable and sticks in the strcpy line and printf line.
Basically this function is to take a string, and a character and removes the that character from the string (because I am learning malloc so that's why I wrote the function like this).
After the while loop do:
copy[j] = '\0';
to NULL-terminate your string; that way it can work with methods coming from <string.h>, which assume that the string is nul-terminated.
PS: One warning you should see is about not returning copy in your function in any case, because now if the condition of the if statement is wrong, your function won't return something valid, so add this:
return copy;
at the end of your function (which is now corrected with your edit).
Other than that, the only warning you should still get are for the unused arguments of main(), nothing else:
prog.c: In function 'main':
prog.c:32:14: warning: unused parameter 'argc' [-Wunused-parameter]
int main(int argc, char * argv[]){
^~~~
prog.c:32:27: warning: unused parameter 'argv' [-Wunused-parameter]
int main(int argc, char * argv[]){
^~~~
While you copy over bytes from str to copy, you don't add a terminating null byte at the end. As a result, strcmp reads past the copied characters into unitialized memory, possibly past the end of the allocated memory block. This invokes undefined behavior.
After your while loop, add a terminating null byte to copy.
Also, you never return a value if the if block at the end is false. You need to return something for that, probably the copied string.
char * removeChar(char * str, char c){
int len = strlen(str);
int i = 0;
int j = 0;
char * copy = malloc(sizeof(char) * (len + 1));
while(i < len){
if(str[i] != c){
copy[j] = str[i];
j++;
i++;
}else{
i++;
}
}
// add terminating null byte
copy[j] = '\0';
if(strcmp(copy, str) != 0){
strcpy(str,copy);
}
// always return copy
return copy;
}
You never initialised input and the some compilers don't notice,
that the the value is never used before the line
input = removeChar(str, 'g');
in your code. So they emit the diagnostic just to be sure.
strcpy(str, copy)
gets stuck in your code, as copy never got a closing 0 byte and
so depends on the nondeterministic content of your memory at the
moment of the allocation of the memory backing copy, how long strcpy
will run and if you get eventually a SIGSEGV (or similar).
strcpy will loop until it finds a 0 byte in your memory.
For starters to remove a character from a string there is no need to create dynamically a character array and then copy this array into the original string.
Either you should write a function that indeed removes the specified character from a string or a function that creates a new string based on the source string excluding the specified character.
It is just a bad design that only confuses users. That is the function is too complicated and uses redundant functions like malloc, strlen, strcmp and strcpy. And in fact it has a side effect that is not obvious. Moreover there is used incorrect type int for the length of a string instead of the type size_t.
As for your function implementation then you forgot to append the terminating zero '\0' to the string built in the dynamically allocated array.
If you indeed want to remove a character from a string then the function can look as it is shown in the demonstrative program.
#include <stdio.h>
char * remove_char(char *s, char c)
{
char *p = s;
while (*p && *p != c) ++p;
for ( char *q = p; *p++; )
{
if (*p != c) *q++ = *p;
}
return s;
}
int main( void )
{
char str[] = "Input string";
puts(str);
puts(remove_char(str, 'g'));
return 0;
}
The program output is
Input string
Input strin
If you are learning the function malloc and want to use it you in any case should try to implement a correct design.
To use malloc you could write a function that creates a new string based on the source string excluding the specified character. For example
#include <stdio.h>
#include <stdlib.h>
char * remove_copy_char(const char *s, char c)
{
size_t n = 0;
for (const char *p = s; *p; ++p)
{
if (*p != c) ++n;
}
char *result = malloc(n + 1);
if (result)
{
char *q = result;
for (; *s; ++s)
{
if (*s != c) *q++ = *s;
}
*q = '\0';
}
return result;
}
int main( void )
{
char *str = "Input string";
puts(str);
char *p = remove_copy_char(str, 'g');
if ( p ) puts(p );
free(p);
return 0;
}
The program output will be the same as above.
Input string
Input strin
Pay attention to the function declaration
char * remove_copy_char(const char *s, char c);
^^^^^^
In this case the source string can be a string literal.
char *str = "Input string";
All I want to ask a question that if we have two string but these should be in the given code
#include<stdio.h>
#include<stdlib.h>
#include <string.h>
char *getln()
{
char *line = NULL, *tmp = NULL;
size_t size = 0, index = 0;
int ch = EOF;
while (ch) {
ch = getc(stdin);
if (ch == EOF || ch == '\n')
ch = 0;
if (size <= index) {
size += index;
tmp = realloc(line, size);
if (!tmp) {
free(line);
line = NULL;
break;
}
line = tmp;
}
line[index++] = ch;
}
return line;
}
char * combine(char *a,char *buffer){
int stop_var;
int newSize = strlen(a) + strlen(buffer) + 1;
char * newBuffer = (char *)malloc(newSize);
strcpy(newBuffer,a);
strcat(newBuffer,buffer); // or strncat
//printf("Final String %s",newBuffer);
free(a);
a = newBuffer;
return newBuffer;
}
char * fun(char *str)
{
char *str1;
str1=getln();
str=combine(str,str1);
return str;
}
int main(void)
{
char *str;
str= getln();
printf("Initial String %s \n",str);
str=fun(str);
printf("Final String %s \n",str);
}
this code is working fine but string char *str="Fixed value" is fixed is gives runtime error
int main(void)
{
char *str;
str= "Fixed Value";
printf("Initial String %s \n",str);
str=fun(str);
printf("Final String %s \n",str);
}
So, I want to know is it any other way to run the above case in which the string is fixed. I know that "How can we achieve the final value in the same character pointer".
Please Read Note:
There are many Questions related to this question I have tried all the solutions.
I looked the below solutions
concatenate-two-char-arrays-into-single-char-array-using-pointers
concatenate-two-char-arrays
how-to-concatenate-pointer-arrays
concatenate-char-array-in-c
concatenate-two-arrays-using-void-pointer-c
I have searched many more solutions over the internet, but no solutions are fulfilled my condition. These all the solution is using the third variable and showing its value. I want value in the same variable. Even if we are creating any extra variable, its value finally should be assign to char *str.
Please provide me any suggestion to do this in c language only.
The given question is different from my question because in that question they checking the behaviour of the string literals bu for my case I am looking to assigns concatenate value to variable str. And its solution changing pointer to an array but I cannot change because its value is using many functions for my work.
Your function combine() calls free() on its first argument. In your fun() call, which is passed from fun() which points to a string literal in your code.
You cannot call free() on a string literal, that's undefined behaviour. I suggest you to restructure your code so that combine() no longer calls free() on its first argument. Freeing memory should be the callers responsibility.
I would suggest pairs of allocation/deallocation functions:
char * combine_allocate(const char *a, const char *b) {
char* result = malloc(...)
combine ...
return result;
}
void combine_deallocate(char* p) { free(p); }
Having that:
char* a = initial_allocate();
char* b = initial_allocate();
char* c = combine_allocate(a, b);
initial_deallocate(a);
initial_deallocate(b);
// ... use c
combine_deallocate(c)
You may omit (and should) initial_allocate/initial_deallocate for string literals.
It might be a bit too verbose, but object oriented C does nothing else (with nicer function names).