How is it possible that the length of this string is increasing? - c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * odd(const char * S, char * dest);
int main()
{
char * source = "abcdefghijklmnopacegiacegi";
unsigned int length = strlen(source);
char dest[length];
printf("%s\n",odd(source, dest));
}
char * odd(const char * source, char * dest)
{
int count = 0;
unsigned int length = strlen(source);
for(int i = 0; i < length; i++)
{
if( (source[i] %2 )!= 0)
{
dest[count] = source[i];
count++;
}
}
return dest;
}
the size of dest increases and produces garbage for any values after the length of source

You have to manually include the ending \0 to the string, that is, at the end of add, you have to add:
dest[count] = '\0';
You know, the length of strings in C is accounted searching for the \0 character. You have to include one of those at the end of each C string. If not, the string may contain any garbage till the first \0 that will be printed.
Finally, when creating dest, you have also to increase the length of the reserved space in one to accomodate that ending 0 character. The strlen does not count that ending 0 character.

Your odd function forgets to NUL-terminate dest, so printf continues to read happily past the intended end of the string, outputting the garbage that happens to be on the stack.
Also, dest must be one character longer, since strlen tells the length of the string not including the closing NUL, thus, if source is by chance all of odd characters, you have a (small) buffer overflow.

You don't copy the terminating \0.

Related

I'm trying to copy a string array onto another string array but in reverse

I want to copy a string array onto another string array, but this other string array would be in reverse. (for example: stop becomes pots).
Here is the code that I write:
#include <stdio.h>
#include <string.h>
int main(){
char notreversed[] = {};
int i, k, length;
scanf("%s", notreversed);
length = strlen(notreversed);
char reversed[length];
for(i=0; i<length ; i++ ){
reversed[i] = notreversed[length-i];
}
printf("%s", reversed);
}
My plan was to use for loop to put in the string from the array one by one, but it always gave me an "exit status 116" error. May I know the reason why?
You must allocate enough space to notreversed to store your string read.
length-i should be length-1-i.
Terminating null-character must be added to reversed before printing via %s.
#include <stdio.h>
#include <string.h>
int main(void){
char notreversed[102401] = {}; /* allocating 100KiB, hoping this is enough... */
int i, k, length;
scanf("%102400s", notreversed); /* add size limit to avoid buffer overrun */
length = strlen(notreversed);
char reversed[length+1]; /* +1 for terminating null-character */
for(i=0; i<length ; i++ ){
reversed[i] = notreversed[length-1-i]; /* fix index */
}
reversed[length] = '\0'; /* add terminating null-character */
printf("%s", reversed);
}

snprintf() in C treats the lowest two bytes of the destination String not individually

I wanted to write a little program which should reverse characters of a string using the snprintf() function in the following way. That's where I noticed something strange.
int main() {
char dest[5] = "";
char source[5] = "abc";
for (int i = 0; i < 4; i++) {
char c = source[i];
snprintf(dest, 5, "%c%s", c, dest); //here, the current character gets appended in front
//of the String "dest" using snprintf() "recursively"
}
}
What the program should output: cba
The actual output: ccba
When debugging the program you can see that the lowest two bytes (dest[0] and dest[1]) always carry the same information.
Does someone know why this happens and how to prevent this?
If I don't use dest twice in the argument but instead use a temporary buffer like: snprintf(temporary, 5, "%c%s", c, dest) and snprintf(dest, 5, "%s", temporary) directly afterwards everything works as expected.
What you are doing is not allowed by the C standard. From section 7.21.6.5 regarding the snprintf function:
The snprintf function is equivalent to fprintf , except that the
output is written into an array (specified by argument s ) rather than
to a stream. If n is zero, nothing is written, and s may be a null
pointer. Otherwise, output characters beyond the n-1 st are
discarded rather than being written to the array, and a null character
is written at the end of the characters actually written into
the array. If copying takes place between objects that overlap,
the behavior is undefined.
So you can't have the destination be one of the sources. You need to write to a temp string.
If the source and destination overlap, memmove can be used.
#include <stdio.h>
#include <string.h>
int main(){
char dest[5] = "";
char source[5] = "abc";
size_t len = strlen ( source);
for ( size_t i = 0; i < len; i++) {
memmove ( &dest[1], &dest[0], len);//move len bytes in array of [5]
dest[0] = source[i];//set first byte
dest[len] = 0;//ensure zero terminator
printf ( "%s\n", dest);
}
}
If recursion is desired then this can be used.
#include <stdio.h>
size_t strreverse(char *str, size_t index, char *dest) {
char ch = str[index];
if(str[index] =='\0') {
return 0;
}
index = strreverse ( str, index + 1, dest);//recursion
dest[index] = ch;
return index + 1;
}
int main ( void) {
char text[] = "abc";
char result[sizeof text] = "";
strreverse ( text, 0, result);
printf("%s\n", text);
printf("%s\n", result);
return 0;
}

Concatenating strings in C. newline in output

I have strange problem where the output of the concatenation comes with a new line between each string input. I tried couple of different things eg. removing the dynamic memory allocation, copying strings into one another and then concatenating. the same issue is there. any ideas why?
Input:
> one
> two
Output:
> Result of concatenation: one
> two
here is the code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
/* code */
char string1[100];
char string2[100];
char *concat;
fgets(string1,100,stdin);
fgets(string2,100,stdin);
unsigned int size = strlen(string1) + strlen(string2);
concat = (char *) malloc(sizeof(char) * size);
if (concat==NULL)
{
exit(0);
}
strcat(concat,string1);
strcat(concat,string2);
printf("Result of concatenation: %s",concat);
return 0;
}
For starters the function fgets can append the new line character to the entered strings. You should remove it. For example
fgets(string1,100,stdin);
string1[ strcspn( string1, "\n" ) ] = '\0';
fgets(string2,100,stdin);
string2[ strcspn( string2, "\n" ) ] = '\0';
Secondly you forgot about the terminating zero when was allocating memory. Instead of
unsigned int size = strlen(string1) + strlen(string2);
You have to write
size_t size = strlen(string1) + strlen(string2) + 1;
Futhermore the allocated memory is not initislaized. You have to write
concat[0] = '\0';
before these statements
strcat(concat,string1);
strcat(concat,string2);
And do not forget to free the allocated memory.
free( concat );
From the man page:
char *fgets(char *restrict s, int n, FILE *restrict stream);
...
The fgets() function shall read bytes from stream into the array
pointed to by s, until n−1 bytes are read, or a <newline> is read
and transferred to s, or an end-of-file condition is encountered.
The string is then terminated with a null byte.
You are likely including the \n (new line characters) read by fgets in your concatenated array of characters.

Inplace string replacement in C

Write a function
void inplace(char *str,
const char pattern,
const char* replacement,
size_t mlen)
Input:
str: a string ending with \0. the input indicates that we need an inplace algorithm.
pattern: a letter.
replacement: a string.
mlen: the size of the memory holds the string str starts from the beginning of the memory and that mlen should be larger than strlen(str)
The final result is still pointed by str.
Note that all occurrence of pattern should be replaced.
For example,
helelo\0...........
Here "helelo" is the string to replace with '\0' at the end. After '\0' there are still L valid bytes. We want to replace "e" by "123".
A simple approach works like this, we go through str, when a pattern is matched, we shift all the rest with the place to fill the replacement string, then replace the pattern by the replacement.
If the original string is with length n and contains only e, we need (n-1) + (n-2) + ... + 1 shifts.
Is there an algorithm that scans the string with only one pass and constant memory cost?
I think two passes is the minimum. On the first pass, count the number of characters that will be replaced. Given that count and the length of the replacement string, you can compute the length of the final string. (And you should verify that it's going to fit into the buffer.)
On the second pass, you scan the string backwards (starting at the last character), copying characters to their final location. When you encounter the search character, copy the replacement string to that location.
In your example, the increase in length would be 2. So you would
copy str[5] which is '\0' to str[7]
copy str[4] which is 'o' to str[6]
copy str[3] which is 'l' to str[5]
copy str[2] which is 'l' to str[4]
at str[1] you find the 'e' so str[3]='3' str[2]='2' str[1]='1'
At this point the output index is the same as the input index, so you can break the loop.
As #chux pointed out in the comments, the cases where the replacement string is either empty, or has exactly one character, can be handled with a single forward pass through the string. So the code should handle those cases separately.
A candidate single pass solution.
For each character in str, recurse. After the recursion, do the replacement.
It does recurse heavily.
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
// return 0:success else 1:fail
static int inplace_help(char *dest, const char *src, int pattern,
const char* replacement, size_t rlen, size_t mlen) {
printf("'%p' '%s' %c\n", dest, src, pattern);
if (*src == pattern) {
if (rlen > mlen) return 1;
if (inplace_help(dest + rlen, src + 1, pattern, replacement, rlen,
mlen - rlen)) return 1;
memcpy(dest, replacement, rlen);
return 0;
}
if (mlen == 0) return 1;
int replace1 = *src;
if (*src) {
if (inplace_help(dest + 1, src + 1, pattern, replacement, rlen, mlen - 1)) {
return 1;
}
}
*dest = replace1;
return 0;
}
void inplace(char *str, const char pattern, const char* replacement,
size_t mlen) {
if (pattern == 0) return;
if (mlen == 0) return;
if (*replacement == 0) return; // Insure str does not shrink.
inplace_help(str, str, pattern, replacement, strlen(replacement), mlen - 1);
}
int main(void) {
char str[1000] = "eeeeec";
inplace(str, 'e', "1234", sizeof str);
printf("'%s'\n", str); // --> '12341234123412341234c'
return 0;
}
The following assumes that the memory allocated to the string has been initialized to something at some point in time, since standard C does not seem to allow access to uninitialized memory. In practice, it will work fine.
It does precisely two scans: the first one is over the entire allocated space, and moves the string to the right-hand edge of the space. The second scan is over the string itself, which it moves back to the left-hand edge while it does replacements.
I changed the prototype to return 0 on success; -1 on failure. I also allow the pattern to be a string. (Maybe a single character was intentional? Easy to change, anyway.) (As written, pattern must not be length zero. Should be checked.)
int inplace(char *str,
const char* pattern,
const char* replacement,
size_t mlen) {
/* We don't know how long the string is, but we know that it ends
with a NUL byte, so every time we hit a NUL byte, we reset
the output pointer.
*/
char* left = str + mlen;
char* right = left;
while (left > str) {
if (!*--left) right = str + mlen;
*--right = *left;
}
/* Naive left-to-right scan. KMP or BM would be more efficient. */
size_t patlen = strlen(pattern);
size_t replen = strlen(replacement);
for (;;) {
if (0 == strncmp(pattern, right, patlen)) {
right += patlen;
if (right - left < replen) return -1;
memcpy(left, replacement, replen);
left += replen;
} else {
if (!(*left++ = *right++)) break;
}
}
return 0;
}

C - Increment a number within a char

Is it possible to increment a number alone within a string?
So let's say I have:
char someString = "A0001";
Is there a way to increment the number '0001'? To make it A0002, A0003 etc?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
char *strinc(const char *str, int d, int min_width){
char wk[12];//12:max length of sizeof(int)=4
char *p;
int len, d_len, c;
c = len = strlen(str);
while(isdigit(str[--c]));
++c;
d += strtol(&str[c], NULL, 10);
if(d<0) d = 0;
d_len = sprintf(wk, "%0*d", min_width, d);
p = malloc((c+d_len+1)*sizeof(char));
strncpy(p, str, c);
p[c]='\0';
return strcat(p, wk);
}
int main(void){
char *someString = "A0001";
char *label_x2, *label_x3;
label_x2 = strinc(someString, +1, 4);
printf("%s\n", label_x2);//A0002
label_x3 = strinc(label_x2, +1, 4);
printf("%s\n", label_x3);//A0003
free(label_x2);
label_x2 = strinc("A0008", +5, 4);
printf("%s\n", label_x2);//A0013
free(label_x3);
label_x3 = strinc(label_x2, -8, 4);
printf("%s\n", label_x3);//A0005
free(label_x2);
free(label_x3);
return 0;
}
no u cannot do it because it is a constant
The simple answer is that there is no "easy" way to do what you're asking. You would have to parse the string, extract the numerical portion and parse into a number. Increment the number and then print that number back into your string.
You could try the following simple example to base something on...
EDIT: Just read BLUEPIXY's answer... he presents a nice function that will do it for you, return you a new string, which doesn't have the width restriction of my simple answer...
There are some points worth noting...
Use char someString[] = "A0001"; and not char *someString = "A0001";. The reason is that the former allocates memory on the stack for the string, the latter is a pointer to a string in memory. The memory location decided upon by the compiler in the latter case and is not always guaranteed to be writable.
Crappy #define for snprintf on Windows... not sure that's a good thing. The point is really use a safe buffer writing function that won't overflow the bounds of your array.
The snprintf format string "%0*u" Formats an unsigned integer with a minimum width specified by the argument to the left of the actual integer and the zero tells it to left pad with zeros if necessary.
If your number increases to a width greater than, in this case, 4 digits, the buffer won't overflow, but your answers will look wrong (I haven't put in any logic to increment the buffer size)
I am assuming the the format of the string is always a set of non-numerical-digits, followed by a set of numerical digits and then a null terminator.
Now the code...
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#ifdef WIN32
#define snprintf sprintf_s
#endif
int main(int argc, char* argv[])
{
/* Assume that the string format is letters followed by numbers */
/* Note use someString[] and NOT someString* */
char someString[] = "A0001";
char *start = someString;
char *end = start + strlen(someString); /* End points to the NULL terminator */
char *endOfParse;
char c;
unsigned long num;
ptrdiff_t numDigits;
/* Find first numeric value (start will point to first numeric
* value or NULL if none found */
while( true )
{
c = *start;
if( c == '\0' || isdigit(c) )
break;
++start;
}
if( c == '\0' )
{
printf("Error: didn't find any numerical characters\n");
exit(EXIT_FAILURE);
}
/* Parse the number pointed to by "start" */
num = strtoul(start, &endOfParse, 0);
if(endOfParse < end )
{
printf("Error: Failed to parse the numerical portion of the string\n");
exit(EXIT_FAILURE);
}
/* Figure out how many digits we parsed, so that we can be sure
* not to overflow the buffer when writing in the new number */
numDigits = end - start;
num = num + 1;
snprintf(start, numDigits+1, "%0*u", numDigits, num); /* numDigits+1 for buffer size to include the null terminator */
printf("Result is %s\n", someString);
return EXIT_SUCCESS;
}
You can't do it simply because its not as simple to machine as it looks to you. There are a lot of things you need to understand about what you are trying to do first. For example, What part of string are you taking as a number which is to be incremented?
Last digit only?
A number which will be followed by SINGLE alphabet?
A number which may be followed by any number of alphabets?
LAST number in a string, for example A33B43 would mean to increment 33 or 43?
When you have answers to all such questions, you can implement them in a function. One of the many possible approaches thereafter can be to make a new substring which will represent the number to be incremented(this substring is to be taken out from your someString). Then use atoi() to convert that string into number, increment the number and replace this incremented number as a string in someString.(someString needs to be String or char * btw).

Resources