In C, If I have:
char *reg = "[R5]";
and I want
char *reg_alt = "R5" (equal to the same thing, but without the brackets), how do I do this?
I tried
*char reg_alt = reg[1:2];
but this doesn't work.
There is no built-in syntax for dealing with substrings like that, so you need to copy the content manually:
char res[3];
memcpy(res, ®[1], 2);
res[2] = '\0';
I suggest you need to read a basic text on C, rather than assuming techniques from other languages will just work.
First, char *reg = "[R5]"; is not a string. It is a pointer, that is initialised to point to (i.e. its value is the address of) the first character of a string literal ("[R5]").
Second, reg_alt is also a pointer, not a string. Assigning to it will contain an address of something. Strings are not first class citizens in C, so the assignment operator doesn't work with them.
Third, 1:2 does not specify a range - it is actually more invalid syntax. Yes, I know other languages do. But not C. Hence my comment that you cannot assume C will allow things it the way that other languages do.
If you want to obtain a substring from another string, there are various ways. For example;
char substring[3];
const char *reg = "[R5]"; /* const since the string literal should not be modified */
strncpy(substring, ®[1], 2); /* copy 2 characters, starting at reg[1], to substring */
substring[2] = '\0'; /* terminate substring */
printf("%s\n", substring);
strncpy() is declared in standard header <string.h>. The termination of the substring is needed, since printf() %s format looks for a zero character to mark the end.
When using null-terminated strings (the default in C), you can indeed cheaply create a substring of another string by simply changing the starting character pointer, but you cannot make the new substring have a different null-terminator.
An option is to use a Pascal-string library. Pascal-strings are length-prefixed instead of C-strings which are null-terminated, which means Pascal-strings can share contents of a larger string buffer and substring generation is cheap (O(1)-cheap). A Pascal string looks like this:
struct PString {
size_t length;
char* start;
}
PString substring(const PString* source, size_t offset, size_t length) {
// Using C99 Designated Initializer syntax:
return PString { .length = length, .start = source.start + offset };
}
The downside is that most of the C library and platform libraries use null-terminated strings and unless your Pascal-string ends in a null character you'll need to copy the substring to a new buffer (in O(n) time).
Of course, if you're feeling dangerous (and using mutable character buffers) then you can hack it to temporarily insert a null-terminator, like so:
struct CStr {
char* start;
char* end;
char temp;
}
CStr getCStr(PString* source) {
char* terminator = (source.start + source.length);
char previous = *terminator;
*terminator = '\0';
return CStr { .start = source.start, .end = terminator, .temp = previous };
}
void undoGetCStr(CStr cstr) {
*cstr.end = cstr.temp;
}
Used like so:
PString somePascalString = doSomethingWithPascalStrings();
CStr temp = getCStr( somePascalString );
printf("My Pascal string: %s", temp.start ); // using a function that expects a C-string
undoGetCStr( temp );
...which then gives you O(1) PString-to-CString performance, provided you don't care about thread-safety.
Need to be a char?
Because that only work when is a "string"
So maybe you need this
char reg[] = "[R5]";
Then you can do the other thing
or just split the string like this question
Related
I need help :/
On textfile, I have something like this:
MyName: 15 3
and I want to read each element until ':' and store it in variable name of the struct, and read the next elements and store 15 and 3 in another variables.
typedef struct STRUCT_PLAYER{char name[20];
int sucess;
int numQuest;
int wrongs;} PLAYER;
int readTop(PLAYER playTop[]){
char *classify = "classificacao.txt";
FILE *fl;
fl = fopen(classify, "r");
char c;
int n=0;
if(cl==NULL){
printf("Error reading the file %s\n", classify);
exit(1);
}
else{
while(c!=EOF){
while(c!=':'){
c=getc(fl);
if(c!=':') playTop[n].name=c;
}
if(c==':')fscanf(fl, " %d %d\n", &playTop[n].numQuest, &playTop[n].wrongs);
n++;
}
}
return n;
this is my code, but it appears me an error, on this line
if(c!=':') playerTOP[n].nome=c;
error: assignment to expression with array type
but I don't understand what it is
c is char, playTop->name is a char[], so your are assigning incompatible types. Also
coderredoc answer
Array name is not a modifiable lvalue
When you initialize your structure do:
int n=0;
playTop[n].name[0] = 0;
...
while(c!=':'){
char cs[] = { getc(fl), 0 };
if(c!=':')
strcat(playTop[n].name, cs);
}
With this cs is a C-String containing one letter only and strcat appends
the string to playTop[n].name, thus saving the name
EDIT
Ricardo's comment
thank you. but I din't understant why you put a zero on char cs[] = { getc(fl), 0}
That is what I was talking about in the comment. In C a string must be
'\0'-terminated.
A C-String is a sequence of bytes. This sequence must end with the value 0.
Every value in the sequence represents a character based on the
ASCII encoding, for example the
character 'a' is 97, 'b' is 98, etc. The character '\0' has
the value 0 and it's the character that determines the end of the string.
That's why you hear a lot that C-Strings are '\0'-terminated.
In C you use an array of chars (char string[], char string[SOME VALUE]) to
save a string. For a string of length n, you need an array of dimension n+1, because
you also need one space for the terminating '\0' character.
When dealing with strings, you always have to think about the proper type,
whether your are using an array or a pointer. A pointer
to char doesn't necessarily mean that you are dealing with a C-String!
Let's take a look at
char str1[] = "Hallo";
char str2[] = { 'H', 'a', 'l', 'l', 'o', 0 };
Both declarations do the same thing, they initialized the arrays str1 and
str2 with 6 elements. str1[5] and str2[5] will be the same: 0 (or '\0'
in its char notation).
A string literal is the text that is wrapped in quotes, "Hello" is a string
literal. Somewhere in the memory of the process the linker puts the sequence
'H', 'a', 'l', 'l', 'o', 0 in memory, usually read-only memory (note the 0
at the end). Even though you don't write the '\0' explicitly, it will have
one.
The '\0' at the end of the sequence of chars is what makes the sequence a
C-String, not the type of the variable. If there is no '\0' at the end, it is not a C-String.
char cs[] = { getc(fl), 0};
is a shorthand of
char cs[2];
cs[0] = getc(fl);
cs[1] = '\0';
By doing the last assignments, I ensure that cs holds a C-String. Most
functions defined in string.h (standard library) expect C-Strings, so they
must be '\0'-terminated.
man strcat
#include <string.h>
char *strcat(char *dest, const char *src);
DESCRIPTION
The strcat() function appends the src string to the dest string,
overwriting the terminating null byte ('\0') at the end of dest, and
then adds a terminating null byte.
From the description you'll see that both dest and src must be strings,
thus '\0'-terminated. That's why I said you should initialize
playTop->name[0] with 0, so that is will be a valid (and empty) string. Only
then I can use strcat.
Luckily there are many ways to archive the same results. If you don't want to
use strcat you could do it also this way:
int name_idx = 0;
while(c!=EOF){
while(c!=':'){
c=getc(fl);
if(c!=':') playTop[n].name[name_idx++]=c;
}
if(c == ':')
{
// make sure that playTop[n].name is a c-string
playTop[n].name[name_idx] = 0;
fscanf(...);
}
...
}
One last thing:
It's not bad using an array for saving strings, the problem is that the
maximum length of the string is dimension or array - 1. In your case the
name must not be longer than 19 characters, otherwise you will have a buffer
overflow and you are going to write over memory that is not allocated for the
name, you will have undefined behaviour and anything could happen.
When you know that the max. length of your string won't pass certain value
(let's say 15), then it's fine to use char name[20]. If there's no guarantee
of a max. length, then you have to dynamically allocate memory for it using
malloc/realloc (and later you would have to free that memory).
Also, a better way to parse your line would be to use fgets to get the while
line and then parse it:
typedef struct STRUCT_PLAYER{char *name;
int sucess;
int numQuest;
int wrongs;} PLAYER;
int readTop(PLAYER playTop[]){
...
char line[1024];
fgets(line, sizeof line, fl);
int colon_index = strchr(line, ':');
// color_index is the index where : is in the line,
// the length of the name is colon_index - 1
// because you have to save \0 as well, you need to
// allocate one more space for the c-string
// name length + 1 ==> (colon_index - 1) + 1
// which equeals to colon_index
playTop[n].name = malloc(colon_index);
// copy the name from line into name. strncpy
// copies at most `colon_index - 1` characters, if
// \0 is not among them, it won't be appended at the end
// you have to do that
strncpy(playTop[n].name, line, colon_index - 1);
// making sure that name becomes a c-string
playTop[n].name[colon_index] = 0;
// sscanf is like fscan, only it takes the content from
// a string and not from a FILE object.
// line + colon_index + 1 ensures that sscanf reads only
// after the colon
sscanf(line + colon_index + 1, "...", ...);
}
Doing it this way, you ensure that the name can have any length. Note that
all these functions may fail: for example malloc might return NULL if
there is not enough memory, strchr might return NULL if a colon is not
found in the line (the line has a wrong format or is empty). The line itself could be
longer than 1024 bytes. For sake of simplicity I've omitted all those checks.
If you've understood my code, then you could make it better by checking for
the errors mentioned above. Read carefully the documentation of the functions
used here.
name is an array of characters and since you are copying character by character, need to use playTop[n].name[x]=c; since name is a character pointer doesn't make sense to compiler when you try to assign a character to it.
Array name is not a modifiable lvalue. You are assigning to it. Violating rules. That's why compiler complained. Even if it was modifiable you are having an incompatibility in type. Assigning a char to char[].
More logical would be to do this
playerTOP[n].nome[some_index]=c;
You have to store those characters in the nome member array of the struct.(which is a char array not char).
Also make int c and then do the check c!=EOF.
the whole, bug ridden:
while(c!=EOF){
while(c!=':'){
c=getc(fl);
if(c!=':') playTop[n].name=c;
}
if(c==':')fscanf(fl, " %d %d\n", &playTop[n].numQuest, &playTop[n].wrongs);
can be easily reduced (and should be reduced) to the clean:
while( 3 == fscanf( fl, " %19[^:]: %d %d",
playTop[n].name,
&playtop[n].numQuest,
&playTop[n].wrongs ) )
{
n++;
}
I am new to C and am having some troubles with strings. How do I create a string of variable length containing a specified character in C? This is what I have tried but I get a compiler error:
int cLen = 8 /* Specified Length */
char chr = 'a'; /* Specified Character */
char outStr[cLen];
int tmp = 0;
while (tmp < cLen-1)
outStr[tmp++] = chr;
outStr[cLen-1] = '\0';
/* outStr = "aaaaaaaa" */
You can try:
char *str = malloc(cLen + 1);
memset(str, 'a', cLen);
str[cLen] = 0;
Strings in C might not be as flexible as you want, on the first look.
What you did with "char outStr[]" was to indicate you'd like a pointer to char, that can be iterated with array syntax... it creates no actual storage for the characters, because you never mentioned how many you would like to store.
In C you can have the storage decoupled from these special variables, called pointers. The example of wanting a variable length string is actually a good example of why would you want that: I want an entity that holds knowledge of where the storage is at; I want methods to allow me to change the storage size.
So, you prepare yourself to deal with dynamic memory allocation by including
#include <stdlib.h>
declare a pointer to chars by
char *cpString;
you ask for an allocation of "n" chars with
cpString=malloc(n*sizeof(char));
Now you can strcat, printf, whatever you want to do with a string that has n-1 charaters (because it must be null terminated).
Specifically, you can now initialize your string with
memset(cpString,X,n-1);
cpString[n]=0;
which creates a XXXX...XXX\0 string, of n-1 characters.
When you want to change cpString storage size, here's the tricky part, you need to free the allocated memory before you request for a new storage allocation
if (cpString !=0)
{
free(cpString);
cpString=0;
}
cpString=malloc(n*sizeof(char));
otherwise the dynamic memory storage area (called a "heap") is left with an un-reclaimable piece of the old n size.
There are better allocators, that don't need free(), but I better leave you studying and practicing with malloc() free() usage.
There's no need to use strncat(), strings are just character arrays so do the assignment directly character by character:
void repeated_string(char *out, size_t len, char v)
{
for(; len > 0; --len)
*out++ = v;
*out = '\0';
}
There are two issues with your code:
1) the length is (probably) not what you're expecting. You have:
int cLen = 8; /* Specified Length */
Presumably you want a string of length 8. Because you have to add a NULL terminator, you're only getting a string of length 7 right now. If that's what you want you should just update your comment to make that clear:
int cLen = 9; /* Specified Length (8) + 1 for NULL */
2) you're not assigning the char correctly:
char chr = "a";
is not right. Characters are specified with a single quote:
char chr = 'a';
After that your code should work.
I'm not used to C as I'm primarily a Java guy, with some knowledge of C++, so forgive me if this is a trivial question. I could not seem to find an answer while searching online.
I'm initializing a char array...
char tcp[50];
So that I can concatenate a const char and a char. In examples I saw an easy way to do this was by creating that empty char array and then using...
strcat(x,y);
To stick them together.
Problem is, printing out the blank char array when it is set to "50" gives me a result of:
X??|?
When I change it to...
char tcp[100];
And print it, its blank. Why is this?
The array contents are undefined, assuming it is a local (automatic) array.
Use:
char tcp[50] = "";
Or:
char tcp[50] = {0};
Or:
char tcp[50];
tcp[0] = 0;
Or:
char tcp[50];
memset(tcp, 0, sizeof(tcp));
As you like.
Always null terminate you char arrays before doing anything:
tcp[0] = '\0';
C happily allocates the space for the array you declare, but it does not set its content to 0.
Therefore, the content of the array you're printing is random (or rather depending in the previous contents of the memory)
When creating an array, the compiler puts it somewhere in memory but does not initialize it, so whatever is in that memory when the program is started will be the initial "string".
Terminate the string manually after you created the array, either by making the whole array "zeroed" out, or just put zero as the first character:
char tcp[50] = { '\0' };
Or
char tcp[50];
/* ... */
tcp[0] = '\0';
The difference here is, you're essentially working with two empty arrays trying to merge them in the memory space of one (not sure if that makes sense for you).
First of all, in C you have to terminate strings with \0. That's something not exposed or visible in Java. Also you essentially used two undefined strings (as there's no value set).
#include <stdio.h>
#include <string.h>
char target[256];
const char source_a[] = "Hello";
const char source_b[] = "World!";
int void(main)
{
target[0] = '\0'; // this essentially empties the string as we set the first entry to be the end. Depending on your language version of C, you might as well write "char target[256] = {'\0'};" above.
strcat(target, source_a); // append the first string/char array
strcat(target, " "); // append a const string literal
strcat(target, source_b); // append the second string
printf("%s\n", target);
return 0;
}
Important: Using strcat() can be unsave, as there's no length check performed, and other than Java, these "strings" have a fixed length (the one you set when defining the variables). If there's no length given, but you copy a string on initialization, that length is taken (e.g. char test[] = "Hello!"; will be 7 chars long (due to terminating \0)).
If you'd like a more Java like approach on strings, use C++ and the std::string class, that performs a lot more similar to Java's strings.
I have a string pointer like below,
char *str = "This is cool stuff";
Now, I've references to this string pointer like below,
char* start = str + 1;
char* end = str + 6;
So, start and end are pointing to different locations of *str. How can I copy the string chars falls between start and end into a new string pointer. Any existing C++/C function is preferable.
Just create a new buffer called dest and use strncpy
char dest[end-start+1];
strncpy(dest,start,end-start);
dest[end-start] = '\0'
Use STL std::string:
#include
const char *str = "This is cool stuff";
std::string part( str + 1, str + 6 );
This uses iterator range constructor, so the part of the C-string does not have to be zero-terminated.
It's best to do this with strcpy(), and terminate the result yourself. The standard strncpy() function has very strange semantics.
If you really want a "new string pointer", and be a bit safe with regard to lengths and static buffers, you need to dynamically allocate the new string:
char * ranged_copy(const char *start, const char *end)
{
char *s;
s = malloc(end - start + 1);
memcpy(s, start, end - start);
s[end - start] = 0;
return s;
}
If you want to do this with C++ STL:
#include <string>
...
std::string cppStr (str, 1, 6); // copy substring range from 1st to 6th character of *str
const char *newStr = cppStr.c_str(); // make new char* from substring
char newChar[] = new char[end-start+1]]
p = newChar;
while (start < end)
*p++ = *start++;
This is one of the rare cases when function strncpy can be used. Just calculate the number of characters you need to copy and specify that exact amount in the strncpy. Remember that strncpy will not zero-terminate the result in this case, so you'll have to do it yourself (which, BTW, means that it makes more sense to use memcpy instead of the virtually useless strncpy).
And please, do yourself a favor, start using const char * pointers with string literals.
Assuming that end follows the idiomatic semantics of pointing just past the last item you want copied (STL semantics are a useful idiom even if we're dealing with straight C) and that your destination buffer is known to have enough space:
memcpy( buf, start, end-start);
buf[end-start] = '\0';
I'd wrap this in a sub-string function that also took the destination buffer size as a parameter so it could perform a check and truncate the result or return an error to prevent overruns.
I'd avoid using strncpy() because too many programmers forget about the fact that it might not terminate the destination string, so the second line might be mistakenly dropped at some point by someone believing it unnecessary. That's less likely if memcpy() were used. (In general, just say no to using strncpy())
I have a string:
char * someString;
If I want the first five letters of this string and want to set it to otherString, how would I do it?
#include <string.h>
...
char otherString[6]; // note 6, not 5, there's one there for the null terminator
...
strncpy(otherString, someString, 5);
otherString[5] = '\0'; // place the null terminator
Generalized:
char* subString (const char* input, int offset, int len, char* dest)
{
int input_len = strlen (input);
if (offset + len > input_len)
{
return NULL;
}
strncpy (dest, input + offset, len);
return dest;
}
char dest[80];
const char* source = "hello world";
if (subString (source, 0, 5, dest))
{
printf ("%s\n", dest);
}
char* someString = "abcdedgh";
char* otherString = 0;
otherString = (char*)malloc(5+1);
memcpy(otherString,someString,5);
otherString[5] = 0;
UPDATE:
Tip: A good way to understand definitions is called the right-left rule (some links at the end):
Start reading from identifier and say aloud => "someString is..."
Now go to right of someString (statement has ended with a semicolon, nothing to say).
Now go left of identifier (* is encountered) => so say "...a pointer to...".
Now go to left of "*" (the keyword char is found) => say "..char".
Done!
So char* someString; => "someString is a pointer to char".
Since a pointer simply points to a certain memory address, it can also be used as the "starting point" for an "array" of characters.
That works with anything .. give it a go:
char* s[2]; //=> s is an array of two pointers to char
char** someThing; //=> someThing is a pointer to a pointer to char.
//Note: We look in the brackets first, and then move outward
char (* s)[2]; //=> s is a pointer to an array of two char
Some links:
How to interpret complex C/C++ declarations and
How To Read C Declarations
You'll need to allocate memory for the new string otherString. In general for a substring of length n, something like this may work for you (don't forget to do bounds checking...)
char *subString(char *someString, int n)
{
char *new = malloc(sizeof(char)*n+1);
strncpy(new, someString, n);
new[n] = '\0';
return new;
}
This will return a substring of the first n characters of someString. Make sure you free the memory when you are done with it using free().
You can use snprintf to get a substring of a char array with precision:
#include <stdio.h>
int main()
{
const char source[] = "This is a string array";
char dest[17];
// get first 16 characters using precision
snprintf(dest, sizeof(dest), "%.16s", source);
// print substring
puts(dest);
} // end main
Output:
This is a string
Note:
For further information see printf man page.
You can treat C strings like pointers. So when you declare:
char str[10];
str can be used as a pointer. So if you want to copy just a portion of the string you can use:
char str1[24] = "This is a simple string.";
char str2[6];
strncpy(str1 + 10, str2,6);
This will copy 6 characters from the str1 array into str2 starting at the 11th element.
I had not seen this post until now, the present collection of answers form an orgy of bad advise and compiler errors, only a few recommending memcpy are correct. Basically the answer to the question is:
someString = allocated_memory; // statically or dynamically
memcpy(someString, otherString, 5);
someString[5] = '\0';
This assuming that we know that otherString is at least 5 characters long, then this is the correct answer, period. memcpy is faster and safer than strncpy and there is no confusion about whether memcpy null terminates the string or not - it doesn't, so we definitely have to append the null termination manually.
The main problem here is that strncpy is a very dangerous function that should not be used for any purpose. The function was never intended to be used for null terminated strings and it's presence in the C standard is a mistake. See Is strcpy dangerous and what should be used instead?, I will quote some relevant parts from that post for convenience:
Somewhere at the time when Microsoft flagged strcpy as obsolete and dangerous, some other misguided rumour started. This nasty rumour said that strncpy should be used as a safer version of strcpy. Since it takes the size as parameter and it's already part of the C standard lib, so it's portable. This seemed very convenient - spread the word, forget about non-standard strcpy_s, lets use strncpy! No, this is not a good idea...
Looking at the history of strncpy, it goes back to the very earliest days of Unix, where several string formats co-existed. Something called "fixed width strings" existed - they were not null terminated but came with a fixed size stored together with the string. One of the things Dennis Ritchie (the inventor of the C language) wished to avoid when creating C, was to store the size together with arrays [The Development of the C Language, Dennis M. Ritchie]. Likely in the same spirit as this, the "fixed width strings" were getting phased out over time, in favour for null terminated ones.
The function used to copy these old fixed width strings was named strncpy. This is the sole purpose that it was created for. It has no relation to strcpy. In particular it was never intended to be some more secure version - computer program security wasn't even invented when these functions were made.
Somehow strncpy still made it into the first C standard in 1989. A whole lot of highly questionable functions did - the reason was always backwards compatibility. We can also read the story about strncpy in the C99 rationale 7.21.2.4:
The strncpy function
strncpy was initially introduced into the C library to deal with fixed-length name fields in
structures such as directory entries. Such fields are not used in the same way as strings: the
trailing null is unnecessary for a maximum-length field, and setting trailing bytes for shorter
5 names to null assures efficient field-wise comparisons. strncpy is not by origin a “bounded
strcpy,” and the Committee preferred to recognize existing practice rather than alter the function
to better suit it to such use.
The Codidact link also contains some examples showing how strncpy will fail to terminate a copied string.
I think it's easy way... but I don't know how I can pass the result variable directly then I create a local char array as temp and return it.
char* substr(char *buff, uint8_t start,uint8_t len, char* substr)
{
strncpy(substr, buff+start, len);
substr[len] = 0;
return substr;
}
strncpy(otherString, someString, 5);
Don't forget to allocate memory for otherString.
#include <stdio.h>
#include <string.h>
int main ()
{
char someString[]="abcdedgh";
char otherString[]="00000";
memcpy (otherString, someString, 5);
printf ("someString: %s\notherString: %s\n", someString, otherString);
return 0;
}
You will not need stdio.h if you don't use the printf statement and putting constants in all but the smallest programs is bad form and should be avoided.
Doing it all in two fell swoops:
char *otherString = strncpy((char*)malloc(6), someString);
otherString[5] = 0;
char largeSrt[] = "123456789-123"; // original string
char * substr;
substr = strchr(largeSrt, '-'); // we save the new string "-123"
int substringLength = strlen(largeSrt) - strlen(substr); // 13-4=9 (bigger string size) - (new string size)
char *newStr = malloc(sizeof(char) * substringLength + 1);// keep memory free to new string
strncpy(newStr, largeSrt, substringLength); // copy only 9 characters
newStr[substringLength] = '\0'; // close the new string with final character
printf("newStr=%s\n", newStr);
free(newStr); // you free the memory
Try this code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char* substr(const char *src, unsigned int start, unsigned int end);
int main(void)
{
char *text = "The test string is here";
char *subtext = substr(text,9,14);
printf("The original string is: %s\n",text);
printf("Substring is: %s",subtext);
return 0;
}
char* substr(const char *src, unsigned int start, unsigned int end)
{
unsigned int subtext_len = end-start+2;
char *subtext = malloc(sizeof(char)*subtext_len);
strncpy(subtext,&src[start],subtext_len-1);
subtext[subtext_len-1] = '\0';
return subtext;
}