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).
Related
I want to check C string length and if it is valid (\0 termination).
So far I have this:
#include <stdio.h>
char good_str[32] = "123456789012345"; // 15 chars with `\0` is ok
char bad_str[32] = "1234567890123456"; // 16 chars with `\0` is too long
int check_max_len(char * s, int max_len){
for (int i = 0; i < max_len; i++) {
if (s[i] == 0)
return 0; // not too long
}
return 1; // too long or no `\0`
}
int main() {
int is_bad;
is_bad = check_max_len((char*)&good_str, 16);
printf("Good string: %i\n", is_bad);
is_bad = check_max_len((char*)&bad_str, 16);
printf("Bad string: %i\n", is_bad);
return 0;
}
I guess this will work well for my application, but maybe there are some "industry standards", or some function in standard library for that?
There is a standard function strnlen() from the string.h header file which comes fairly close to functionality you are looking for. It takes 2 parameters: a string (const char*) and a maximum read length (size_t) respectively.
It looks like this:
size_t strnlen(const char* str, size_t max_len);
It will return the quantity of bytes pointed to by the passed string, excluding the terminating null character if encountered within the the passed max_len.
Logically speaking, this function still requires you to know the expected string length so that way you can have an accurate results. Without that information, your program will error out or it will do unexpected things such as reading into other strings, and data. Hence why you should make it clear that you expect null terminated strings to begin with.
I'm still a newbie to C so please forgive me if anything below is wrong. I've searched this up online but nothing really helped.
Right now, I have the following code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void appendStr (char *str, char c)
{
for (;*str;str++); // note the terminating semicolon here.
*str++ = c;
*str++ = 0;
}
int main(){
char string[] = "imtryingmybest";
char result[] = "";
for(int i = 0; i < strlen(string); i++){
if(i >= 0 && i <= 3){
appendStr(result, string[i]);
}
}
printf("%s", result);
}
Basically, I'm trying to add the first 4 characters of the String named string to result with a for loop. My code above did not work. I've already tried to use strcat and strncat and neither of them worked for me either. When I used
strcat(result, string[i]);
It returns an error saying that the memory cannot be read.
I know that in this example it might have been easier if I just did
appendStr(result, string[0]);
appendStr(result, string[1]);
appendStr(result, string[2]);
appendStr(result, string[3]);
But there is a reason behind why I'm using a for loop that couldn't be explained in this example.
All in all, I'd appreciate it if someone could explain to me how to append individual characters to a string in a for loop.
The following code doesnt use your methods but successfully appends the first 4 chars to result
#include <stdio.h>
#include <string.h>
int main()
{
// declare and initialize strings
char str[] = "imtryingmybest";
char result[5]; // the 5th slot is for \0 as all strings are null terminated
// append chars to result
strncat(result, str, 4);
// ^ ^ ^
// | | |- number of chars to be appended
// | | - string to be appended from
// | - string to append to
// print string
printf("result: %s\n", result);
return (0);
}
The result of the above is as wanted:
>> gcc -o test test.c
>> ./test
result: imtr
Let me know if anything is not clear so i can elaborate further
string was ruined by the overflow of result buffer.
appendStr can be executed only once. next time strlen(string) will return 0. because *str++ = 0; has been written to the space of string.
result buffer has only 1 byte space, but you write 2 byte to it in appendStr call.
the second byte will ruin string space.
I suggest debug with gdb.
try to get rid of Magic numbers
#define BUFF_SIZE 10 // define some bytes to allocate in result char array
#define COPY_COUNT 4 // count of chars that will be copied
int main(){
char string[] = "imtryingmybest";
char result[BUFF_SIZE] {}; // allocate some chunk of memory
for(size_t i = 0; i < strlen(string); i++){
if(i < COPY_COUNT){
appendStr(result, string[i]);
}
}
printf("%s", result);
}
I showed the solution code Paul Yang showed the problem
As others have pointed out the code has a simple mistake in the allocation of the destination string.
When declaring an array without specifying its size, the compiler deduces it by its initializer, which in your case means a 0 + the NULL character.
char result[] = ""; // means { '\0' };
However, I think that the bigger issue here is that you're effectively coding a Schlemiel.
C strings have the serious drawback that they don't store their length, making functions that have to reach the end of the string linear in time complexity O(n).
You already know this, as shown by your function appendStr()
This isn't a serious issue until start you appending characters or strings in a loop.
In each iteration of your loop appendStr() reaches the last character of the string, and extends the string, making the next iteration a little slower.
In fact its time complexity is O(n²)
Of course this is not noticeable for small strings or loops with few iterations, but it'll become a problem if the data scales.
To avoid this you have to take into account the growing size of the string.
I modified appendStr() to show that now it starts from the last element of result
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void appendStr (char *str, char c, char *orig)
{
printf("i: %ld\n", str - orig);
for (; *str; str++); // note the terminating semicolon here.
*str++ = c;
*str++ = 0;
}
int main()
{
char string[32] = "imtryingmybest";
char result[32] = "";
for(int i = 0; i < strlen(string); i++) {
if(i >= 0 && i <= 3) {
// I'm passing a pointer to the last element of the string
appendStr(&result[i], string[i], result);
}
}
printf("%s", result);
}
You can run it here https://onlinegdb.com/HkogMxbG_
More on Schlemiel the painter
https://www.joelonsoftware.com/2001/12/11/back-to-basics/
https://codepen.io/JoshuaVB/pen/JzRoyp
I wrote a program that is supposed to solve this this problem. "Write a program that, given a string, a width, and an empty string for output, centers the string in the output area. Use a function that returns 1 if the formatting is successful and 0 if any errors, such as string is greater then length". My problem is that the my program just returns a lot of odd characters when it prints the string out. And it won't flag 0. What can I do to fix my code and or solve the problem better?
FULL CODE:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int formatString(char str[250], char strcopy[250], int width);
int main()
{
char str[250];
char strcopy[250];
int width;
int outcome;
printf("Enter some text:\n");
gets(str);
printf("\nEnter a width (to check): ");
scanf("%d", &width);
printf("What you entered:");
printf("| %s |\n", str);
printf("\n");
outcome = formatString(str, strcopy, width);
if (outcome = 1)
{
printf("String copied.\n");
printf("| %s |", strcopy);
}
else
{
printf("Use a width val. that is the length of string\n");
}
return 0;
}
int formatString(char str[250], char strcopy[250], int width)
{
int sapceCheck;
int temp = 0;
sapceCheck = width - 1;
for (int i = 0; i < width; i++)
{
if (str[i] == '\0')
{
printf("Formating sucessful\n");
strncpy(str, strcopy, sizeof(str)-1); * (str + (sizeof(str) - 1)) = '\0';
temp = 1;
}
}
if (temp == 0)
{
return 0;
}
else
{
printf("Formating not sucessful\n");
printf("Width does not work\n");
return 0;
}
}
Don't miss the answer posted by 'Soravux', which contains all the right advice about how to fix the 'question' code.
Here is an alternate approach. However, the caller must ensure that the destination string 'strcpy' is large enough (length+1) to hold the output:
int formatString(char *str, char *strcopy, int length)
{
size_t strLength;
strLength = strlen(str);
/* Check if the string is greater than the length */
if(strLength > length)
return(0);
/* Print the centered 'str' to 'strcopy'. */
sprintf(strcopy, "%*s%*s",
(length+strLength) / 2, str, //leading spaces & 'str'
length - ((length+strLength) / 2), "" //trailing spaces
);
return(1);
}
A side note on your problem: returning 1 on success and 0 on failure is not the standard function behavior in C literature (aside from functions returning a boolean). Are you following a guide or a course?
You should not arbitrarily pre-allocate 250 chars for your strings. Strings are most often represented by char pointers, handled with dynamic memory allocation. I understand that gets() takes a pre-allocated buffer, but this is a really bad practice. You should consider using the fgets() function and use its maximum number of characters argument for a better security. Hard-coding string length is also hard to maintain (multiple places to modify the length) as well as confusing for readers (it's not clear if the compiler will pass the argument by copy or by reference).
Also, don't try to hide your code. The line containing the strncpy() have two statements, with the unary star pending in-between the two, looking like a multiplication operator. Don't do such things. Put the second statement on a new line.
That being said, you also misunderstood the arguments from the strncpy function: it is destination first, followed by source. You copy an uninitialized buffer (strcopy) into your string. Note that you also misinterpret the value of your temp variable which returns an error when something went well. It also returns 0 instead of 1 as asked.
Last notice: you really should break; your for-loop in your function formatString(), otherwise your strncpy will be executed for every \0 in your string.
I would recommend to check for exercises in a book if you are self-taught or seek the assistance of a TA if you are following a course. They will be able to guide you in the right path for understanding your mistakes.
In C, how do I check if a string read from a file contains a 10 digit number. I have used strspn and it seems to work, but I think there are better ways. Any help greatly appreciated.
char cset[] = "1234567890";
do
{
// read line into line_string
} while (strspn(line_string, cset) != 10);
It should work. Are you sure you read the line_string correctly?
char cset[] = "1234567890";
char line[] = "9846578497";
printf("%d", strspn(line, cset));
outputs 10. A simple loop that explicitly checks every character is quite straightforward too:
int i, digits = 0;
for (i = 0; line[i] != '\0'; ++i) // <-- make sure line is null-terminated
if (isdigit(line[i])) digits++;
printf("%d", digits);
There's a much eaiser way, use the string.h library
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, const char *argv[])
{
char string[] = "0123456789";
int stringLength = strlen(string);
printf("%d\n", stringLength);
return 0;
}
It depends on what you wanted.
Let's presume a bunch of different inputs. For that we have:
char cset[] = "1234567890";
char str1[] = "5319764208"; /* all digits in different order */
strspn(str1, cset); /* returns 10 */
char str2[] = "098765432"; /* not all digits present */
strspn(str2, cset); /* returns 9 */
char str3[] = "not098a7654num321"; /* not a number, but has all digits */
strspn(str3, cset); /* returns 0 */
char str4[] = "blah 1234567890 blah"; /* all digits in same order plus chars */
strspn(str4, cset); /* returns 0 */
So it depends on what you intended acceptable input to be.
Yes there are many efficient ways but it depends how you are going to use them in your program. There are commands depending on your context of use, you can read on "strncmp" and "strstr".
If you want to compare for string in the starting of the line you can use,strncmp here is the example.
#define VALID_STRING " <project"
#define COMPARELIMIT 10
if(!strncmp(linebuffer, VALID_STRING, COMPARELIMIT)) {
// your code goes here
}
else {
}
if you want to compare at any other point in the line buffer use "strstr"
#define CHECK_STRING "name="
char *start=NULL;
start=strstr(linebuffer, CHECK_STRING);
// it returns the address pointing to the first character of that(CHECK_STRING) string any where in linebuffer.
#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.