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).
Related
My str_split function returns (or at least I think it does) a char** - so a list of strings essentially. It takes a string parameter, a char delimiter to split the string on, and a pointer to an int to place the number of strings detected.
The way I did it, which may be highly inefficient, is to make a buffer of x length (x = length of string), then copy element of string until we reach delimiter, or '\0' character. Then it copies the buffer to the char**, which is what we are returning (and has been malloced earlier, and can be freed from main()), then clears the buffer and repeats.
Although the algorithm may be iffy, the logic is definitely sound as my debug code (the _D) shows it's being copied correctly. The part I'm stuck on is when I make a char** in main, set it equal to my function. It doesn't return null, crash the program, or throw any errors, but it doesn't quite seem to work either. I'm assuming this is what is meant be the term Undefined Behavior.
Anyhow, after a lot of thinking (I'm new to all this) I tried something else, which you will see in the code, currently commented out. When I use malloc to copy the buffer to a new string, and pass that copy to aforementioned char**, it seems to work perfectly. HOWEVER, this creates an obvious memory leak as I can't free it later... so I'm lost.
When I did some research I found this post, which follows the idea of my code almost exactly and works, meaning there isn't an inherent problem with the format (return value, parameters, etc) of my str_split function. YET his only has 1 malloc, for the char**, and works just fine.
Below is my code. I've been trying to figure this out and it's scrambling my brain, so I'd really appreciate help!! Sorry in advance for the 'i', 'b', 'c' it's a bit convoluted I know.
Edit: should mention that with the following code,
ret[c] = buffer;
printf("Content of ret[%i] = \"%s\" \n", c, ret[c]);
it does indeed print correctly. It's only when I call the function from main that it gets weird. I'm guessing it's because it's out of scope ?
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define DEBUG
#ifdef DEBUG
#define _D if (1)
#else
#define _D if (0)
#endif
char **str_split(char[], char, int*);
int count_char(char[], char);
int main(void) {
int num_strings = 0;
char **result = str_split("Helo_World_poopy_pants", '_', &num_strings);
if (result == NULL) {
printf("result is NULL\n");
return 0;
}
if (num_strings > 0) {
for (int i = 0; i < num_strings; i++) {
printf("\"%s\" \n", result[i]);
}
}
free(result);
return 0;
}
char **str_split(char string[], char delim, int *num_strings) {
int num_delim = count_char(string, delim);
*num_strings = num_delim + 1;
if (*num_strings < 2) {
return NULL;
}
//return value
char **ret = malloc((*num_strings) * sizeof(char*));
if (ret == NULL) {
_D printf("ret is null.\n");
return NULL;
}
int slen = strlen(string);
char buffer[slen];
/* b is the buffer index, c is the index for **ret */
int b = 0, c = 0;
for (int i = 0; i < slen + 1; i++) {
char cur = string[i];
if (cur == delim || cur == '\0') {
_D printf("Copying content of buffer to ret[%i]\n", c);
//char *tmp = malloc(sizeof(char) * slen + 1);
//strcpy(tmp, buffer);
//ret[c] = tmp;
ret[c] = buffer;
_D printf("Content of ret[%i] = \"%s\" \n", c, ret[c]);
//free(tmp);
c++;
b = 0;
continue;
}
//otherwise
_D printf("{%i} Copying char[%c] to index [%i] of buffer\n", c, cur, b);
buffer[b] = cur;
buffer[b+1] = '\0'; /* extend the null char */
b++;
_D printf("Buffer is now equal to: \"%s\"\n", buffer);
}
return ret;
}
int count_char(char base[], char c) {
int count = 0;
int i = 0;
while (base[i] != '\0') {
if (base[i++] == c) {
count++;
}
}
_D printf("Found %i occurence(s) of '%c'\n", count, c);
return count;
}
You are storing pointers to a buffer that exists on the stack. Using those pointers after returning from the function results in undefined behavior.
To get around this requires one of the following:
Allow the function to modify the input string (i.e. replace delimiters with null-terminator characters) and return pointers into it. The caller must be aware that this can happen. Note that supplying a string literal as you are doing here is illegal in C, so you would instead need to do:
char my_string[] = "Helo_World_poopy_pants";
char **result = str_split(my_string, '_', &num_strings);
In this case, the function should also make it clear that a string literal is not acceptable input, and define its first parameter as const char* string (instead of char string[]).
Allow the function to make a copy of the string and then modify the copy. You have expressed concerns about leaking this memory, but that concern is mostly to do with your program's design rather than a necessity.
It's perfectly valid to duplicate each string individually and then clean them all up later. The main issue is that it's inconvenient, and also slightly pointless.
Let's address the second point. You have several options, but if you insist that the result be easily cleaned-up with a call to free, then try this strategy:
When you allocate the pointer array, also make it large enough to hold a copy of the string:
// Allocate storage for `num_strings` pointers, plus a copy of the original string,
// then copy the string into memory immediately following the pointer storage.
char **ret = malloc((*num_strings) * sizeof(char*) + strlen(string) + 1);
char *buffer = (char*)&ret[*num_strings];
strcpy(buffer, string);
Now, do all your string operations on buffer. For example:
// Extract all delimited substrings. Here, buffer will always point at the
// current substring, and p will search for the delimiter. Once found,
// the substring is terminated, its pointer appended to the substring array,
// and then buffer is pointed at the next substring, if any.
int c = 0;
for(char *p = buffer; *buffer; ++p)
{
if (*p == delim || !*p) {
char *next = p;
if (*p) {
*p = '\0';
++next;
}
ret[c++] = buffer;
buffer = next;
}
}
When you need to clean up, it's just a single call to free, because everything was stored together.
The string pointers you store into the res with ret[c] = buffer; array point to an automatic array that goes out of scope when the function returns. The code subsequently has undefined behavior. You should allocate these strings with strdup().
Note also that it might not be appropriate to return NULL when the string does not contain a separator. Why not return an array with a single string?
Here is a simpler implementation:
#include <stdlib.h>
char **str_split(const char *string, char delim, int *num_strings) {
int i, n, from, to;
char **res;
for (n = 1, i = 0; string[i]; i++)
n += (string[i] == delim);
*num_strings = 0;
res = malloc(sizeof(*res) * n);
if (res == NULL)
return NULL;
for (i = from = to = 0;; from = to + 1) {
for (to = from; string[to] != delim && string[to] != '\0'; to++)
continue;
res[i] = malloc(to - from + 1);
if (res[i] == NULL) {
/* allocation failure: free memory allocated so far */
while (i > 0)
free(res[--i]);
free(res);
return NULL;
}
memcpy(res[i], string + from, to - from);
res[i][to - from] = '\0';
i++;
if (string[to] == '\0')
break;
}
*num_strings = n;
return res;
}
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";
I have the following simple program that reads character by character a text file. Each time a character is read from the file, must go at the end of the str which is a string. For this reason I made a small function called conc which takes the character, reallocates the str and then takes the character at the end of the string (str[count] = ch).
After the EOF character, I put the '\0' character to the str as an end for the string variable.
My question is why the last printf displays garbage?? Any ideas??
Thanks in advance.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void conc(char* str,char ch,int* count);
int main(int argc,char** argv)
{
char* str = (char*)malloc(sizeof(char));
char ch;
int count = 0,i;
FILE* fp = fopen("path","r");
if(fp == NULL){
printf("No File Found");
return 1;
}
ch=fgetc(fp);
while(ch!=EOF){
conc(str,ch,&count);
ch=fgetc(fp);
}
str[count] = '\0';
printf("%s",str);
free(str);
return(0);
}
void conc(char* str,char ch,int* count){
str[*count] = ch;
(*count)++;
//printf("\n%c",str[(*count)-1]);
str = (char*)realloc(str,(*count)+1);
}
The problem is with how you realloc() the pointer. The changes you do to str will not modify the original pointer in main(). You are only assigning to the copy of the pointer str in conc(). You need to pass a pointer to pointer in order to modify it.
void conc(char** str,char ch,int* count){
(*str)[*count] = ch;
(*count)++;
*str = realloc(*str,(*count)+1);
}
and pass a pointer to it from main():
conc(&str,ch,&count);
Change the prototype to match:
void conc(char** str,char ch,int* count);
Others notes:
1) when realloc() fails it returns NULL and you will lose the original pointer. So you need to use a temporary and assign to the original.
See: Having dynamically allocated an array can I change its size?
2) Casting malloc()/realloc() etc is also dangerous.
3) Always check the return value of malloc() etc to see if the memory allocation failed.
3) Allocating one char at a time is not very efficient. Typical way is to allocate a buffer of size N and double the size when you realloc().
It is not necessary to pass count to your function because you are (or rather, should be) passing it a proper zero terminated string, and the new character should always be added to its end.
If you are going to modify str anyway, it's slightly better to start out with str = NULL. On its first call, set str to occupy 2 bytes to begin with, and add 1 character each next call.
Be careful with char ch; and then using while(ch!=EOF) ..! This will only work when your default char is signed. It will also prematurely stop when you encounter a byte 0FFh in your input.
With these points in mind, I end up with this:
char *conc (char *str, char ch);
int main (void)
{
char *str = NULL;
int ch;
FILE* fp = fopen("path","r");
if(fp == NULL){
printf("No File Found");
return 1;
}
ch=fgetc(fp);
while(ch!=EOF)
{
str = conc (str, ch);
ch = fgetc(fp);
}
printf("%s",str);
free(str);
return 0;
}
char *conc (char *str, char ch)
{
int last_pos;
if (str)
{
last_pos = strlen(str);
str = realloc (str, last_pos+1);
} else
{
str = malloc(2);
last_pos = 0;
}
str[last_pos] = ch;
str[last_pos+1] = 0;
return str;
}
I'm fairly new to C and I'm trying to work out dynamic memory allocation for reading from a file. At least I think that's what I'm doing.
Anyway, this code works:
int readfromfile(FILE *filepointer)
{
size_t size = 2;
char *str = (char *) malloc(sizeof(char));
int character = 0;
size_t counter = 0;
while((character = fgetc(filepointer)) != EOF)
{
str = (char *) realloc(str, size);
str[counter] = (char) character;
size ++;
counter++;
}
str[counter] = '\0';
printf("+%s+", str);
free(str);
return 0;
}
And this code does not:
int main()
{
char *str = (char *) malloc(sizeof(char));
...
readfromfile(ifpointer, &str);
}
int readfromfile(FILE *filepointer, char **str)
{
size_t size = 2;
int character = 0;
size_t counter = 0;
while((character = fgetc(filepointer)) != EOF)
{
*str = (char *) realloc(*str, size);
*str[counter] = (char) character;
size ++;
counter++;
}
str[counter] = '\0';
printf("+%s+", *str);
free(str);
return 0;
}
I cannot understand why because as far as I understand I'm sending a pointer to the location of the char array to the function and accessing the data everytime. The compilers shows no error messages, it just loops through once and on the second loop crashes after the realloc every time. The character assigned to the first value is garbage too.
I have spent an age trying to get this to worked and done a lot of research so I apologise if I've missed a solution but I'm truly stuck at this point.
You get a crash because
*str[counter] = (char) character;
is the same as
*(str[counter]) = (char) character;
as opposed to
(*str)[counter] = (char) character;
which is actually what you wanted. Read Operator Precedence on Wikipedia. You'll find that [] has more precedence than the * (dereference operator).
Also, the cast here, as well as in the calls to realloc and malloc, is unnecessary. Don't forget to check the return value of realloc, malloc etc to see if they were successful in allocating memory.
Now, you have another problem: free(str); in the second code should be free(*str);. Note that after *str has been freed from the function, you aren't supposed to read or write into this memory location from main as it has now become invalid for you to tamper with.
in your int readfromfile(FILE *filepointer, char **str) the parameter char **str is actually the same as char *str[], which means **str is expecting an array of char pointers. however you're passing to it char *str which is just an array of char
when you use readfromfile(...) you should do it this way (something like...):
char *str[2] = {"some char array", "another char array"};
readfromfile(ifpointer, str);
or:
char *a = "this char array";
char **str = &a[0];
readfromfile(ifpointer, str);
you'll get the idea...
Im trying to remove the first char of the string and keep the remainder, my current code doesnt compile and im confused on how to fix it.
My code:
char * newStr (char * charBuffer)
{
int len = strlen(charBuffer);
int i = 1;
char v;
if(charBuffer[0] == 'A' || charBuffer[0] == 'Q'){
for(i=1;i<len;i++)
v = v + charBuffer[i];
}
v = v + '\0';
return v;
}
Gcc: "Warning: return makes pointer from integer without a cast"
Also: "char * newStr (char * charBuffer)" needs to remain the same.
Strings don't work like this in C. You're summing up all of the characters in the buffer into the v variable. You can't use + to concatenate. The code you posted has some serious problems which indicate that there's an understanding gap with how to use C.
Try this:
char *newStr (char *charBuffer) {
int length = strlen(charBuffer);
char *str;
if (length <= 1) {
str = (char *) malloc(1);
str[0] = '\0';
} else {
str = (char *) malloc(length);
strcpy(str, &charBuffer[1]);
}
return str;
}
or this:
char *newStr (char *charBuffer) {
char *str;
if (strlen(charBuffer) == 0)
str = charBuffer;
else
str = charBuffer + 1;
return str;
}
Depending on whether you want to allocate a new string or not. You'll also have to add the code for handling the cases that don't start with 'Q' or 'A'. I didn't include those because I'm not sure exactly what you're trying to do here.
Make sure you do some research into allocating and deallocating memory with malloc and free. These are fundamental functions to be able to use if you're going to be doing C programming.
Well, your description says you want to deal with "strings", but you code deals with char buffers/pointers. The simplest approach to remove the first character for strings would be
const char *newStr(const char *string)
{
return string+1;
}
but as that doesn't look at all like what your code is doing, you probabaly want something different. For example, if you want to just remove a leading 'A' or 'Q' and then copy the string to a buffer, you want something like
char *newStr(const char *string)
{
if (string[0] == 'A' || string[0] == 'Q')
string++;
return strdup(string);
}
You can simply move your char pointer one character in:
char* newstring = oldstring + 1;
Your function is declared to return a char * and you are returning a char.
Furthermore, why don't you just return a pointer to the second character?
char * newStr (char * charBuffer)
{
if (charBuffer && (*charBuffer == 'A' || *charBuffer == 'Q')) return charBuffer + 1;
return charBuffer;
}
Several of the other answers recommended returning charBuffer + 1. As I noted in my previous comment:
This is bad practice. What if the string is dynamically allocated? Perhaps eventually the storage will be freed (starting from the second character). The string should be copied to new storage first.
Freeing a piece of storage from the middle will result in undefined behavior.
Instead, try the strdup function which will return a duplicate of the given string.
#include <string.h>
#include <stdio.h>
char *newStr(char* charBuffer) {
if (charBuffer && (charBuffer[0] == 'A' || charBuffer[0] == 'Q'))
return strdup(charBuffer + 1);
else
return strdup(charBuffer);
}
void main() {
char a[7] = "Advait";
char b[5] = "John";
printf("%s\n",newStr(a)); // Prints "dvait"
printf("%s\n",newStr(b)); // Prints "John"
}