Related
hi i'm trying to write a function that get 3 words, concatenate them to one word and print the word reverse.
i can't put the concatenated word into the ptr w1 in concatWords function.
another question - should i put '\0' in the end of every word?
can someone review my code?
thanks!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 10
void initWords(char *w1, char *w2, char *w3) {
printf("Enter first word:\n");
scanf("%10s", w1);
printf("Enter second word:\n");
scanf("%10s", w2);
printf("Enter third word:\n");
scanf("%10s", w3);
}
char* concatWords(char *w1, char *w2, char *w3) {
int len = strlen(w1) + strlen(w2) + strlen(w3);
w1 = (char*)malloc(sizeof(char) * len);
strcat(w1, w2);
strcat(w1, w3);
return w1;
}
void printReversedWord(char *word) {
int len = strlen(word);
for (int i = len - 1; i >=0; i--) {
printf("%c", word);
}
}
int main()
{
char word1[N+1];
char word2[N+1];
char word3[N+1];
char* longWord;
initWords(word1, word2, word3);
longWord = concatWords(word1, word2, word3);
printReversedWord(longWord);
free(longWord);
return 0;
}
You allocate memory that you assign to w1. Whatever w1 was pointing at can therefore not be included in the final string. You need a separate variable for where to put the final result.
Example:
char *concatWords(char *w1, char *w2, char *w3) {
size_t w1len = strlen(w1);
size_t w2len = strlen(w2);
size_t w3len = strlen(w3);
// the final result will be stored in memory pointed out by `res`:
char *res = malloc(w1len + w2len + w3len + 1); // +1 for null terminator
if (res) {
// copy the three strings where they belong:
memcpy(res, w1, w1len);
memcpy(res + w1len, w2, w2len);
memcpy(res + w1len + w2len, w3, w3len + 1); // +1 for null terminator
}
return res;
}
Another issue: printReversedWord is missing the subscript operator on word:
void printReversedWord(char *word) {
for (size_t i = strlen(word); i-- > 0;) {
printf("%c", word[i]); // <- here
}
}
Demo
The function strcat deals with strings. That means that the both function arguments shall point to strings. And the function also builds a string.
Also as your function does not change passed strings then its parameters should have qualifier const. And the function shall build a new string. Otherwise after this statement
w1 = (char*)malloc(sizeof(char) * len);
the first passed string is lost.
The function can look the following way
char * concatWords( const char *w1, const char *w2, const char *w3 )
{
size_t len = strlen( w1 ) + strlen( w2 ) + strlen( w3 );
char *result = malloc( len + 1 );
if ( result != NULL )
{
strcpy( result, w1 );
strcat( result, w2 );
strcat( result, w3 );
}
return result;
}
In turn the function printReversedWord can look the following way/ Pay attention to that your function implementation has a bug in this statement
printf("%c", word);
You have to write
printf("%c", word[i]);
Here is the updated function definition.
void printReversedWord( const char *word )
{
size_t len = strlen( word );
while ( len != 0 )
{
putchar( word[--len] );
}
putchar( '\n' );
}
In main you should write
initWords( word1, word2, word3 );
longWord = concatWords(word1, word2, word3);
if ( longWord != NULL ) printReversedWord(longWord);
free( longWord );
char* concatWords(char *w1, char *w2, char *w3) {
int len = strlen(w1) + strlen(w2) + strlen(w3);
w1 = (char*)malloc(sizeof(char) * len);
strcat(w1, w2);
strcat(w1, w3);
return w1;
}
This method:
allocates memory that is not zeroed out, which will make it impossible to "cat" to it, because that assumes the string is null-terminated.
allocates memory and then overwrites the pointer that points to the first word. That would be lost.
allocates only memory for the three words, but misses the final zero that needs to be written to a null-terminated string
does not communicate clearly, which parameters will or will not be changed be the function
So to fix this:
char* concatWords(const char* w1, const char* w2, const char* w3) {
int len = strlen(w1) + strlen(w2) + strlen(w3);
char* all = calloc(len + 1, sizeof(char));
strcat(all, w1);
strcat(all, w2);
strcat(all, w3);
return all;
}
char* concatWords(char *w1, char *w2, char *w3) {
int len = strlen(w1) + strlen(w2) + strlen(w3);
w1 = (char*)malloc(sizeof(char) * len);
strcat(w1, w2);
strcat(w1, w3);
return w1;
}
This function needs a fair bit of work. I'm assuming you want to allocate a new string sufficiently large for the job, concatenate w1, w2 and w3 into it, and return that new string.
Firstly, you overwrote the pointer for w1 in this line:
w1 = (char*)malloc(sizeof(char) * len);
So (in that function) you've now lost whatever was pointed to by w1, because w1 is now pointed to newly-allocated memory.
Secondly, you've not allocated enough memory to store the string: you need an extra +1 to include the terminal NUL character.
The original values of w1, w2 and w3 passed into the function were cast to (char *) from the base addresses of char[] arrays, so you can't use w1 = realloc(w1, len+1); - you'll need a new variable to store the new pointer.
Your concatWords() function should look like this:
char* concatWords(const char * const w1,
const char * const w2,
const char * const w3) {
int len = strlen(w1) + strlen(w2) + strlen(w3) + 1; // Note the +1!
new_w = (char*)malloc(sizeof(char) * len);
strcpy(new_w, w1);
strcat(new_w, w2);
strcat(new_w, w3);
return new_w;
}
Note that I've changed the function's parameter types, so that you don't accidentally change the values of the w1, w2 or w3 pointers, or the memory they point to. Always use minimum viable permissions, to prevent the risk of memory corruption. In C terms, if you can const it, const it!
Your printReversedWord(char *word) function won't work either. You're passing word to printf() as the argument to its "%c" format string, not the contents of the memory it's pointing to. You never use the index variable i!
This will have the effect of passing either the first or the last byte of the pointer value as the character to print, depending whether your CPU's big-endian or little-endian.
So if word's value as a pointer was 0x12345678 (the location of the first character in the string it points to), you'd either be printing 0x12 (unprintable control character DC2) or 0x78 ('x') over and over again instead of the reversed contents of word. Of course, the actual effect would depend on the real pointer's value, not my example here.
It should be (something like):
void printReversedWord(const char * const word) {
int len = strlen(word);
for (int i = len - 1; i >=0; i--) {
printf("%c", word[i]);
}
printf("\n"); // Don't forget the newline!
}
Note the [i] in the printf() argument. It indexes into the char array pointed to by word. Note also (again) the improvement in the parameter type. I've also added a newline at the end.
Finally, looking at:
#define N 10
void initWords(char *w1, char *w2, char *w3) {
printf("Enter first word:\n");
scanf("%10s", w1);
printf("Enter second word:\n");
scanf("%10s", w2);
printf("Enter third word:\n");
scanf("%10s", w3);
}
You've defined N, but then explicitly embedded 10 in the scanf() format strings. What happens if you change the value of N at a later point?
I'll leave the solution for that as an exercise for the student. :)
The max length of each string is defined in a globally available token... Why not use it (and temporarily use a bit too much dynamic memory)?
char* concatWords(char *w1, char *w2, char *w3) {
char *p = (char*)malloc( (3*N+1) * sizeof *p );
if( p )
sprintf( p, "%s%s%s", w1, w2, w3 );
return p;
}
One could also add checking that all 3 incoming pointers are not NULL...
I'm trying to add a character at a defined position. I've created a new function, allocate a memory for one more char, save characters after the position then added my character at the defined position, and now I don't know how to erase characters after that position to concatenate the saved string. Any solution?
Here is the beginning of my function:
void appendCharact(char *source, char carac, int position) {
source = realloc(source, strlen(source) * sizeof(char) + 1); //Get enough memory
char *temp = source.substr(position); //Save characters after my position
source[position] = carac; //Add the character
}
EDIT :
I'm trying to implement another "barbarous" solution, in debug mode I can see that I've approximately my new string but it look like I can't erase the older pointer...
void appendCharact(char *source, char carac, int position) {
char *temp = (char *)malloc((strlen(source) + 2) * sizeof(char));
int i;
for(i = 0; i < position; i++) {
temp[i] = source[i];
}
temp[position] = carac;
for (i = position; i < strlen(source); i++) {
temp[i + 1] = source[i];
}
temp[strlen(temp) + 1] = '\0';
free(source);
source = temp;
}
I mentioned that I could see five problems with the code as shown (copied here for reference)
void appendCharact(char * source, char carac , int position)
{
source = realloc(source, strlen(source) * sizeof(char) + 1); //Get enough memory
char * temp = source.substr(position); //Save characters after my position
source[position] = carac; //Add the charactere
}
The problems are (in no specific order):
strlen(source) * sizeof(char) + 1 is equal to (strlen(source) * sizeof(char)) + 1. It should have been (strlen(source) + 1) * sizeof(char). However, this works fine since sizeof(char) is defined in the C++ specification to always be equal to 1.
Related to the above: Simple char strings are really called null-terminated byte strings. As such they must be terminated by a "null" character ('\0'). This null character of course needs space in the allocated string, and is not counted by strlen. Therefore to add a character you need allocate strlen(source) + 2 characters.
Never assign back to the pointer you pass to realloc. If realloc fails, it will return a null pointer, making you lose the original memory, and that is a memory leak.
The realloc function return type is void*. In C++ you need to cast it to the correct pointer type for assignment.
You pass source by value, meaning inside the function you have a local copy of the pointer. When you assign to source you only assign to the local copy, the original pointer used in the call will not be modified.
Here are some other problems with the code, or its possible use:
Regarding the null-terminator, once you allocate enough memory for it you also need to add it to the string.
If the function is called with source being a literal string or an array or anything that wasn't returned by a previous call to malloc, calloc or realloc, then you can't pass that pointer to realloc.
You use source.substr(position) which is not possible since source isn't an object and therefore doesn't have member functions.
Your new solution is much closer to a working function but it still has some problems:
you do not check for malloc() failure.
you should avoid computing the length of the source string multiple times.
temp[strlen(temp) + 1] = '\0'; is incorrect as temp is not yet a proper C string and strlen(temp) + 1 would point beyond the allocated block anyway, you should just write temp[i + 1] = '\0';
the newly allocated string should be returned to the caller, either as the return value or via a char ** argument.
Here is a corrected version:
char *insertCharact(char *source, char carac, size_t position) {
size_t i, len;
char *temp;
len = source ? strlen(source) : 0;
temp = (char *)malloc(len + 2);
if (temp != NULL) {
/* sanitize position */
if (position > len)
position = len;
/* copy initial portion */
for (i = 0; i < position; i++) {
temp[i] = source[i];
}
/* insert new character */
temp[i] = carac;
/* copy remainder of the source string if any */
for (; i < len; i++) {
temp[i + 1] = source[i];
}
/* set the null terminator */
temp[i + 1] = '\0';
free(source);
}
return temp;
}
int pos = 1;
char toInsert = '-';
std::string text = "hallo";
std::stringstream buffer;
buffer << text.substr(0,pos);
buffer << toInsert;
buffer << text.substr(pos);
text = buffer.str();
Try using something like:
#include <string>
void appendCharAt(std::string& src, char c , int pos)
{
std::string front(src.begin(), src.begin() + pos - 1 ); // use iterators
std::string back(src.begin() + pos, src.end() );
src = front + c + back; // concat together +-operator is overloaded for strings
}
Not 100% sure weather the positions are right. Maybe front hast to be src.begin() + pos and back src.begin() + pos + 1. Just try it out.
The C version of this will have to take care of the situation where realloc fails, in which case the original string is preserved. You should only overwrite the old pointer with the one returned from realloc upon success.
It might look something like this:
bool append_ch (char** str, char ch, size_t pos)
{
size_t prev_size = strlen(*str) + 1;
char* tmp = realloc(*str, prev_size+1);
if(tmp == NULL)
{
return false;
}
memmove(&tmp[pos+1], &tmp[pos], prev_size-pos);
tmp[pos] = ch;
*str = tmp;
return true;
}
Usage:
const char test[] = "hello word";
char* str = malloc(sizeof test);
memcpy(str, test, sizeof test);
puts(str);
bool ok = append_ch(&str, 'l', 9);
if(!ok)
asm ("HCF"); // error handling here
puts(str);
free(str);
I have a variable called char *inputstr, if the string length given to variable is a an odd number, I need to insert a "0" at the beginning of the string variable inputstr.
For example:
char *inputstr = "1ABc2" .
Now I need to append "0" and make it "01ABc2". How do I achieve this?
char a[2] = "0";
char *inputstr = "1ABc2";
if( strlen (inputstr) % 2 == 0)
{
strcat (a, inputstr);
strcpy (inputstr, a);
}
if( condition)
{
Using inputstr variable // here string value is along with junk characters
}
First, you need to set aside a buffer large enough for your target string:
/**
* Attempting to modify the contents of a string literal leads to undefined
* behavior; to be safe, pointers to literals should be declared "const".
* You are not going to write the modified string back to what inputstr
* points to.
*/
const char *inputstr = "1ABc2";
/**
* Compute the size of the target buffer, which is the length of inputstr
* plus 1 for the leading "0" plus 1 for the string terminator.
*/
size_t targetBufferLength = strlen( inputstr ) + 2;
/**
* Allocate the target buffer. Since targetBufferLength is a run-time
* value, this will only work with C99 and later. If you're using C90
* or earlier, targetBufferLength will have to be a compile-time constant,
* so you'll have to compute it manually and declare it as
*
* char targetBuffer[7]; // 5 + 1 + 1
*
* or
*
* #define TARGETBUFFERLENGTH 7
* ...
* char targetBuffer[TARGETBUFFERLENGTH];
*
*/
char target[targetBufferLength] = {0};
Now you can write your new string to the target buffer. You can use sprintf:
sprintf( target, "%s%s", "0", inputstr );
or you can use a combination of strcpy and strcat (or strncpy and strncat for the paranoid in the room):
strcpy( target, "0" );
strcat( target, inputstr );
Be aware of the potential for buffer overflow with either method. Make sure that your target buffer is large enough for the final string. Using strcpy and strcat is risky, but using strncpy and strncat in their place isn't a guarantee of success either.
You could also allocate the buffer dynamically:
char *target = calloc( targetBufferLength, sizeof *target );
The advantage of this is that you can resize the buffer as necessary if it
isn't big enough:
if ( strlen( target ) + strlen( newStr ) > targetBufferLength )
{
char *tmp = realloc( target, (targetBufferLength + strlen( newStr ) + 1) * sizeof *target );
if ( tmp )
{
target = tmp;
targetBufferLength += strlen( newStr ) + 1;
strcat( target, newStr );
}
else
{
// could not extend target buffer, don't append
}
}
The disadvantage is that you now have memory management issues, and you have to remember to free the buffer when you're done with it.
you can use memmove as the areas overlap but IMO is better to write a simple routine for it:
src - the string to append in front of the dest. dest has to be big enough to accommodate its new characters
char *straddfront(char *dest, const char *src)
{
size_t srclen = strlen(src);
size_t destlen = strlen(dest);
for (int i = 0; i <= destlen; i++)
*(dest + destlen + srclen - i) = *(dest + destlen - i);
strncpy(dest, src, srclen);
return dest;
}
You are searching for strcat (or really better strncat) defined in string.h
But you have to notice:
strcat concatenates two strings, thus you need to use the string "0" as the destination
if destination is not large enough, program behavior is unpredictable
the destination (the first argument of strcat i the only one that is modified, not the second argument (that is actually a const char*)
For reasons that I promise exist, I'm reading input character by character, and if a character meets certain criteria, I'm writing it into a dynamically allocated buffer. This function adds the specified character to the "end" of the specified string. When reading out of the buffer, I read the first 'size' characters.
void append(char c, char *str, int size)
{
if(size + 1 > strlen(str))
str = (char*)realloc(str,sizeof(char)*(size + 1));
str[size] = c;
}
This function, through various iterations of development has produced such errors as "corrupted double-linked list", "double free or corruption". Below is a sample of how append is supposed to be used:
// buffer is a string
// bufSize is the number of non-garbage characters at the beginning of buffer
char *buft = buffer;
int bufLoc=0;
while((buft-buffer)/sizeof(char) < bufSize)
append(*(buft==),destination,bufLoc++);
It generally works for some seemingly arbitrary number of characters, and then aborts with error. If it's not clear what the second code snippet is doing, it's just copying from the buffer into some destination string. I know there's library methods for this, but I need a bit finer control of what exactly gets copied sometimes.
Thanks in advance for any insight. I'm stumped.
This function does not append a character to a buffer.
void append(char c, char *str, int size)
{
if(size + 1 > strlen(str))
str = realloc(str, size + 1);
str[size] = c;
}
First, what is strlen(str)? You can say "it's the length of str", but that's omitting some very important details. How does it compute the length? Easy -- str must be NUL-terminated, and strlen finds the offset of the first NUL byte in it. If your buffer doesn't have a NUL byte at the end, then you can't use strlen to find its length.
Typically, you will want to keep track of the buffer's length. In order to reduce the number of reallocations, keep track of the buffer size and the amount of data in it separately.
struct buf {
char *buf;
size_t buflen;
size_t bufalloc;
};
void buf_init(struct buf *b)
{
buf->buf = NULL;
buf->buflen = 0;
buf->bufalloc = 0;
}
void buf_append(struct buf *b, int c)
{
if (buf->buflen >= buf->bufalloc) {
size_t newalloc = buf->bufalloc ? buf->bufalloc * 2 : 16;
char *newbuf = realloc(buf->buf, newalloc);
if (!newbuf)
abort();
buf->buf = newbuf;
buf->bufalloc = newalloc;
}
buf->buf[buf->buflen++] = c;
}
Another problem
This code:
str = realloc(str, size + 1);
It only changes the value of str in append -- it doesn't change the value of str in the calling function. Function arguments are local to the function, and changing them doesn't affect anything outside of the function.
Minor quibbles
This is a bit strange:
// Weird
x = (char*)realloc(str,sizeof(char)*(size + 1));
The (char *) cast is not only unnecessary, but it can actually mask an error -- if you forget to include <stdlib.h>, the cast will allow the code to compile anyway. Bummer.
And sizeof(char) is 1, by definition. So don't bother.
// Fixed
x = realloc(str, size + 1);
When you do a:
str = (char*)realloc(str,sizeof(char)*(size + 1));
the changes in str will not be reflected in the calling function, in other words the changes are local to the function as the pointer is passed by value. To fix this you can either return the value of str:
char * append(char c, char *str, int size)
{
if(size + 1 > strlen(str))
str = (char*)realloc(str,sizeof(char)*(size + 1));
str[size] = c;
return str;
}
or you can pass the pointer by address:
void append(char c, char **str, int size)
{
if(size + 1 > strlen(str))
*str = (char*)realloc(*str,sizeof(char)*(size + 1));
(*str)[size] = c;
}
I have a character array of length 32 and would like to take certain charcters out of it.
for example
111111000000000000000000111111 <32 chars
I would like to take chars 0-6 which would be 111111
Or even take chars 26-31 which would be 111111
char check_type[32];
Above is how I'm declaring.
What I would like to be able to do is define a function or use a function that takes that starting place, and end character.
Ive looked at many ways like using strncpy and strcpy but found no way yet.
I would simply wrap strncpy:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Creates a sub-string of range [start, end], return value must be freed */
char *substr(char *src, size_t start, size_t end)
{
size_t sub_len = end - start + 1;
char * new_str = malloc(sub_len + 1); /* TODO: check malloc's return value */
strncpy(new_str, src, sub_len);
new_str[sub_len] = '\0'; /* new_str is of size sub_len + 1 */
return new_str;
}
int main(void)
{
char str[] = "111111000000000000000000111111";
char *sub_str = substr(str, 0, 5);
puts(sub_str);
free(sub_str);
return EXIT_SUCCESS;
}
Output:
111111
Use memcpy.
// Stores s[from..to) in sub.
// The caller is responsible for memory allocation.
void extract_substr(char const *s, char *sub, size_t from, size_t to)
{
size_t sublen = to - from;
memcpy(sub, s + from, sublen);
sub[sublen] = '\0';
}
Sample:
char *substr(char *source, int startpos, int endpos)
{
int len = endpos - startpos + 2; // must account for final 0
int i = 0;
char *src, *dst;
char *ret = calloc(len, sizeof(char));
if (!ret)
return ret;
src = source + startpos;
dst = ret;
while (i++ < len)
*dst++ = *src++;
*dst = 0;
return ret;
}
Of course, free the return code when you don't need it anymore. And you notice this function will not check for the validity of endpos vs startpos.
First define the required interface...perhaps:
int substring(char *target, size_t tgtlen, const char *source, size_t src_bgn, size_t src_end);
This takes a destination (target) array where the data will be copied, and is given its length. The data will come from the source array, between positions src_bgn and src_end. The return value will be -1 for an error, and the length of the output (excluding the terminating null). If the target string is too short, you will get an error.
With that set of details in place, you can implement the body fairly easily, and strncpy() might well be appropriate this time (it often isn't).
Usage (based on your question):
char check_type[32] = "111111000000000000000000111111";
char result1[10];
char result2[10];
if (substring(result1, sizeof(result1), check_type, 0, 6) <= 0 ||
substring(result2, sizeof(result2), check_type, 26, 31) <= 0)
...something went wrong...
else
...use result1 and result2...
Check this:
char* Substring(char *string, int len, int start, int end) {
/*
Creates a substring from a given string.
Args:
string: The string whose substring you need to find.
len: The length of the string.
start: The start position for the substring.
end: The end position of the substring (inclusive).
Returns:
substring: (of type char*) which is allocated on the heap.
NULL: on error.
*/
// Check that the start and end position are valid.
// If not valid, then return NULL.
if (start < 0 || start >= len || end < 0 || end >= len) {
return NULL;
}
// Allocate memory to return the substring on the heap.
char *substring = malloc(sizeof(char) * (end - start + 2));
int index = 0, i;
for (i = start; i <= end; i++) {
substring[index] = string[i];
index++;
}
// End with a null character.
substring[index] = '\0';
return substring;
}
int main() {
char str[] = "11111100000000000000000000111111";
printf("%s\n", Substring(str, strlen(str), 0, 5));
printf("%s\n", Substring(str, strlen(str), 26, 31));
}