I have a function that joins two constant char* and returns the result. What I want to do though is join a char to a constant char* eg
char *command = "nest";
char *halloween = join("hallowee", command[0]); //this gives an error
char *join(const char* s1, const char* s2)
{
char* result = malloc(strlen(s1) + strlen(s2) + 1);
if (result)
{
strcpy(result, s1);
strcat(result, s2);
}
return result;
}
The function you wrote requires two C-strings (i.e. two const char * variables). Here, your second argument is command[0] which is not a pointer (const char *) but a simple 'n' character (const char). The function, however, believes that the value you passed is a pointer and tries to look for the string in memory adress given by the ASCII value of the letter 'n', which causes the trouble.
EDIT: To make it work, you would have to change the join function:
char *join(const char* s1, const char c)
{
int len = strlen(s1);
char* result = malloc(len + 2);
if (result)
{
strcpy(result, s1);
result[len] = c; //add the extra character
result[len+1] = '\0'; //terminate the string
}
return result;
}
If you wish to join a single character, you will have to write a separate function that takes the quantity of characters from s2 to append.
The best is to create a new function that allows adding a single char to a string.
But if you would like to use the join() function as it is for some reason, you can also proceed as follows:
char *command = "nest";
char *buffer = " "; // one space and an implicit trailing '\0'
char *halloween;
*buffer = command[0];
halloween = join("hallowee", buffer);
Related
I want to join a char** with a given delimiter:
char *str[] = {"this", "is", "a", "test", NULL};
char* flattened = join(str, ' ');
printf("%s", flattened);
Expected contents of flattened:
this is a test\0
I came up with this implementation:
char* join(char** strs, char delim){
int remaining = 128;
char* res = (char*) malloc(remaining*sizeof(char));
memset(res, '\0', remaining);
char* c;
for(c = *strs; c; c=*(++strs)){
strncpy(res, c, remaining);
remaining-=strlen(c)+1;
res+=strlen(c)+1;
*(++res)=delim;
res++;
}
return res;
}
I do not expected the joined string to exceed 128 characters, therefore I made it static and not calculated by the lengths combined.
The above solution prints an empty string.
I searched for an already tried-and-tested implementation of this but I could not find anything; if anyone can point me into the right direction or help me salvage this, that would be great.
You can simplify your join function greatly by:
Using the calloc() function rather than the combination of malloc() and memset().
Using the index ([]) operator on your strs argument, rather than trying to increment the pointer.
Converting the passed single-char delim argument to a nul-terminate string.
Using the strcat() function to append each string and the separator to your res string.
Here is a version using those techniques:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* join(char** strs, char delim)
{
char* res = calloc(128, sizeof(char)); // Might as well set to zero on allocation
char* c;
char sep[2] = { delim, '\0' }; // Convert single char into a string
int i = 0;
for (c = strs[i]; c; c = strs[++i]) {
strcat(res, c);
strcat(res, sep);
}
return res;
}
int main()
{
char* str[] = { "this", "is", "a", "test", NULL };
char* flattened = join(str, ' ');
printf("%s", flattened);
free(flattened); // Don't forget to free the memory when you're done with it!
return 0;
}
I wrote a function to concatenate two strings (s = "computer"; t = "keyboard"), but my code only returns "keyboard". Please point out the mistakes.
char *concat(char *s, char *t) {
s = malloc((strlen(s) + strlen(t) + 1) * sizeof(char));
char *p = s;
while (*p != '\0') {
++p;
}
while (*t != '\0') {
*p++ = *t++;
}
*p = '\0';
return s;
}
I do not want to use strcat(). This is a test program from Stepik, so I cannot change anything in the main function.
Here is the question: Write a function which receives two character pointers and returns a new character pointer representing their concatenation.
char *myconcat(const char *s1, const char *s2)
{
size_t len1,len2;
char *result = malloc((len1 = strlen(s1)) + (len2 = strlen(s2)) + 1);
if(result)
{
memcpy(result, s1, len1);
memcpy(result + len1, s2, len2 + 1);
}
return result;
}
You have s="computer" when passed into a function, and then on the very first line you reassign it with malloc, so "computer" is gone.
You can debug your program step by step, or just print the values to the console. This will help you to find the error.
You are on the right track:
you allocate the correct amount of memory,
you copy the second string correctly,
you set the null terminator correctly,
you return the pointer to the allocated block.
Yet there are some issues:
you overwrite the pointer to the first string with that returned by malloc(),
you read from the allocated memory block instead of copying the first string: this has undefined behavior,
(minor) the argument strings should be declared as const char * as you do not modify these strings.
Here is a corrected version:
#include <stdlib.h>
#include <string.h>
char *concat(const char *s, const char *t) {
char *ret = malloc((strlen(s) + strlen(t) + 1) * sizeof(char));
char *p = ret;
while (*s != '\0') {
*p++ = *s++;
}
while (*t != '\0') {
*p++ = *t++;
}
*p = '\0';
return ret;
}
On const char * const str = ch; there is a warning:initialization makes pointer from integer without a cast.
If I change it to const char * const str = (char*)ch the warning will be cast to pointer from integer of different size.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv){
FILE *file1;
char ch;
char array[100];
file1 = fopen("list.txt","r");
while((ch=fgetc(file1))!=EOF)
{
const char * const str = (char*)ch;
const char * const delim = "\n";
char * const dupstr = strdup(str);
char *saveptr = NULL;
char *substr = NULL;
int count = 0;
printf("original string is %s",dupstr);
substr = strtok_r(dupstr, delim, &saveptr);
do{
printf("#%d filename is %s\n", count++, substr);
substr = strtok_r(NULL, delim, &saveptr);
}
while(substr);
free (dupstr);
return 0;
}
fclose(file1);
return 0;
}
ch=fgetc(file1))!=EOF is incorrect because ch is a char, but EOF is an int. This is the very reason why fgetc and similar functions return an int. Easiest way to fix the current code is probably to use a temporary int, then copy that to a char inside the loop.
const char * const str = (char*)ch;. Casting from a character to a pointer doesn't make any sense. This is the reason for the warning. If you want to create a temporary string consisting of one character, you should do something like char str[2] = {ch, '\0'}. That way you don't have to use strdup either.
ch is a char (an integral type) and you try to convert it to a pointer type char * (a type that can store an address). These two types are of very different nature, and it is forbidden by the standard to do such. At least convert the address of ch : (char *)&ch.
Beware this will not save your code as you are trying to use a char as a C-string. Again these are of different kind. A char is just something that let you store the code value of a character. A C-string is a sequence of characters terminated by a NUL one.
Suggestions (we don't really know what you try to achieve) : use an array of chars, read a full line from your opened file with fgets, etc.
I have this function:
char *replace_str(char *str, char *orig, char *rep)
{
static char buffer[4096];
char *p;
if(!(p = strstr(str, orig)))
return str;
strncpy(buffer, str, p-str);
buffer[p-str] = '\0';
sprintf(buffer+(p-str), "%s%s", rep, p+strlen(orig));
return buffer;
}
When I use it, it only changes the first instance of the character to be replaced. Is there any way i can make it get it to do this to all said characters?
If I understand correctly, you need a loop that reallocates the beginning of the string after the ending of your replacement string. Indeed, your function performs the action only once, since strstr returns a pointer to the first occurrence of the word orig in str.
EDIT: This may give you an idea of how to do it. I can't test it on this computer, so it might not work directly.
I did it using malloc, since static char shouldn't be used this way, in my opinion. It is supposed to store the values in buffer for a future use of the function. If you re-use this function, you would lose the previous return value of the function...
This is my way of doing it, there is certainly a more efficient way of doing it. The advantage of this function is that it adapts to any string length.
char *replace_str(char *str, char *orig, char *rep)
{
char *buffer;
char *previous_version;
char *p;
size_t occurring_position;
if (strcmp(orig, rep) == 0)
{
return(str);
}
buffer = strdup(str);
while ((p = strstr(buffer, orig)))
{
occuring_position = p - buffer;
previous_version = strdup(buffer);
free(buffer);
buffer = malloc(strlen(previous_version) + strlen(rep) - strlen(orig));
strcnpy(buffer, previous_version, occurring_position);
strcpy(buffer, rep);
strcpy(buffer + occurring_position + strlen(rep), previous_version + occurring_position + strlen(orig));
free(previous_version);
}
return (buffer);
}
Is there a way in C to split a string (using strtok or any other way) where the delimiter is more than one character in length? I'm looking for something like this:
char a[14] = "Hello,World!";
char *b[2];
b[0] = strtok(a, ", ");
b[1] = strtok(NULL, ", ");
I want this to not split the string because there is no space between the comma and the W. Is there a way to do that?
You could just repeatedly call substr to find occurrences of your boundary string and split along the results. After you found a result, advance the pointer by the length of the substring and search again.
You can use char * strstr(const char *haystack, const char *needle) to locate your delimiter string within your string.
char a[14] = "Hello,World!";
char b[2] = ", ";
char *start = a;
char *delim;
do {
delim = strstr(start, b);
// string between start and delim (or end of string if delim is NULL).
start = delim + 2; // Use lengthof your b string.
} while (delim);
Something like this maybe? No guarantees that this compiles. ;)
char* strstrtok(char *haystack, char *needle) {
static char *remaining = null;
char *working;
if(haystack)
working = haystack;
else if(remaining)
working = remaining;
else
return NULL;
char *result = working;
if(result = strstr(working, needle))
remaining = working + strlen(needle) + 1;
return result;
}