How to use strset() in linux using c language - c

I can’t use strset function in C. I'm using Linux, and I already imported string.h but it still does not work. I think Windows and Linux have different keywords, but I can’t find a fix online; they’re all using Windows.
This is my code:
char hey[100];
strset(hey,'\0');
ERROR:: warning: implicit declaration of function strset; did you
meanstrsep`? [-Wimplicit-function-declaration]
strset(hey, '\0');
^~~~~~ strsep

First of all strset (or rather _strset) is a Windows-specific function, it doesn't exist in any other system. By reading its documentation it should be easy to implement though.
But you also have a secondary problem, because you pass an uninitialized array to the function, which expects a pointer to the first character of a null-terminated string. This could lead to undefined behavior.
The solution to both problems is to initialize the array directly instead:
char hey[100] = { 0 }; // Initialize all of the array to zero
If your goal is to "reset" an existing null-terminated string to all zeroes then use the memset function:
char hey[100];
// ...
// Code that initializes hey, so it becomes a null-terminated string
// ...
memset(hey, 0, sizeof hey); // Set all of the array to zero
Alternatively if you want to emulate the behavior of _strset specifically:
memset(hey, 0, strlen(hey)); // Set all of the string (but not including
// the null-terminator) to zero

strset is not a standard C function. You can use the standard function memset. It has the following declaration
void *memset(void *s, int c, size_t n);
For example
memset( hey, '\0', sizeof( hey ) );

Related

Perform special kind of initialization of string in C

As you know in C, we can initialize string variables like this:
char text[1024] =
"Hello "
"World";
But what if I have a function that returns the word "World"?
char text[1024] =
"Hello "
World();
It seems to me that's not possible in C.
Please confirm.
What you want is not possible.
The L-value to the assigment operator needs to be modifyable, which an array isn't.
From the C11-Standard:
6.5.16/2
An assignment operator shall have a modifiable lvalue as its left operand.
The only exception to this is during initialisation when using literals as R-value:
char text[1024] = "Hello ""World";
From the C11-Standard:
6.7.9/14
An array of character type may be initialized by a character string literal or UTF−8 string
literal, optionally enclosed in braces. Successive bytes of the string literal (including the
terminating null character if there is room or if the array is of unknown size) initialize the
elements of the array.
If World() is something that always returns "World", then define it as a macro:
#define World "World"
And then do:
char text[1024] =
"Hello "
World; //Without parentheses
EDIT
String concatenation in the way you expect to do is made by the C preprocessor.You are actually looking for a runtime concatenation of two strings, which can be performed in multiple ways. The simplest one is achieved by strcat function, but the initialization should be performed explicitly by a function:
char text[1024];
void init_text() {
strcpy(text, "Hello ");
strcat(text, World()); //World() defined somewhere else
}
Alternative using sprintf :
void init_text() {
sprintf(text, "Hello %s", World());
}
Then in the main function, call init_text() at the beginning:
int main() {
init_text();
...
}
It is not possible in standard C to initialize something with some runtime specific behavior. So the standard portable way is to initialize the data by calling a function at the beginning of main, as answered by Claudix.
However, if you are using some recent GCC compiler (or Clang/LLVM) you could otherwise, on some systems (including Linux and probably other POSIX systems), use some constructor attribute on function. So you would declare:
static void init_text(void) __attribute__((constructor));
and define init_text like in Claudix's answer without having to call it in your main : since it has the constructor attribute, it would be called magically before main, or during dlopen(3) if it appears inside a dynamically linked plugin or library.
A more portable trick might be to have a function returning that text which will initialize it during its first call. So instead of using text you would call get_my_text() everywhere (perhaps by putting #define text get_my_text() in a header, but I don't recommend doing so for readability reasons, so replace every occurrence of text by get_my_text() ...), and define it as:
const char*get_my_text() {
static char textbuf[1024];
if (textbuf[0]) {
// already initialized, so return it
return textbuf;
};
snprintf(textbuf, sizeof(textbuf), "Hello %s", World());
return textbuf;
}
Beware that such a trick is not reliable in multi-threaded programs: two threads might run get_my_text exactly at the same time, and you have a data race. In a multi-threaded app use e.g. pthread_once
You could even define get_my_text as a static inline function in your header file.
PS Always prefer snprintf(3) to sprintf to avoid buffer overflows. Also notice that in standard C++ any static or global data with some given constructor is initialized before main ... hence the name of GCC function attribute...

Passing c string into function

I have a question regarding passing c string into function.
If I have a function:
void reverse(char* c){
//here is the reverse code
}
In the main:
int main(){
char* c1="abcd";
char c2[5]="abcd";
char * c3=new char[5];
c3="abcd";
}
In my test, only c1 is not allow to pass into the function, other two works fine. I would like to know why c1 is a wrong usage? Thank you very much!
Your code is C++, not C; new char[5] is a syntax error in C.
C and C++ are two different languages. In C++, string literals are const, and passing a string literal to a function that takes a char* argument is an error. You should have gotten an error message (which you haven't bothered to show us) from your C++ compiler.
(If you were using a C compiler, it would have accepted a call like reverse("foo"), but it would have complained about the new char[5].)
c1 will point to a string literal and attempting to modify a string literal is undefined behavior, this is based on the assumption that reverse will attempt to reverse the string in place.

Passing a constant integer when function expects a pointer

What's the best/most cannonical way of passing in a constant integer value to a function that expects a pointer?
For example, the write function
write (int filedes, const void *buffer, size_t size);
Let's say I just want to write a single byte (a 1), I would think this:
write (fd, 1, 1);
but I obviously get the warning
warning: passing argument 2 of 'write' makes pointer from integer without a cast
I know I can do
int i = 1;
write (fd, &i, 1);
but is that necessary? What's the most correct way of doing this without the need of declaring/initializing a new variable?
In C89/90 you can't generally do it without declaring a new variable. The thing about pointers in C is that they always point to lvalues. Lvalue is something that has a location in memory. So, in order to supply the proper argument to your function, you need something that has a location in memory. That normally requires a definition, i.e. an object, a variable. Constants in C are not lvalues, so you can't use a constant there. Things that lie somewhat in between constants and variables are literals. C89/90 has only one kind of literal: string literal. String literals are lvalues, but not variables. So, you can use a string literal as the second argument of write.
In C99 the notion of literal was extended beyond string literals. In C99 you can also use compound literals for that purpose, which also happen to be lvalues. In your example you can call your function as
write(fd, (char[]) { 1 }, 1)
But this feature is only available in C99.
For the specific case you cite, you can do this:
write(fd, "\001", 1);
But, more generally, you must do that about which you are complaining. You must declare an object before taking its address:
SomeType i;
SomeFUnction(&i);
Yes, that's necessary. There's no other way to do this in C that is equally clear, since you can't take the address of/get a pointer to a temporary.
(And, as #rob already said, you should take the address of a char. Your example is non-portable.)
EDIT: See #AndreyT's answer and set your compiler to C99 mode.
An integer isn't a pointer. If you pass it a one, it will dereference virtual address 1 and die. You must make that variable and pass its address.
Write requires an address as is second parameter - live with it.
You can use drprintf() which prints to a file descriptor. It is similar to fprintf() which prints to a FILE *.
int dprintf(int fd, const char *format, ...);
See man 3 dprintf for details.
The functions dprintf() and vdprintf() (as found in the glibc2 library) are exact analogs of fprintf(3) and vfprintf(3), except that they output to a file descriptor fd instead of to a stdio stream.
It is POSIX.1 compliant, not universal.
write(var, new int(4))
This seems to work. Not sure how good this is as I haven't used c++ that much.
Let me know if this is a bad way to do this.

Conflicting types Warning when passing String to function in C

I haven't programmed in C for awhile and having an issue with passing a string to a function.
The code works however I get warnings from gcc.
I call the function in my main with:
copyToCode(code, section1, section2);
The function is:
void copyToCode (char **code, char *loc, char *data ){}
I get "conflicting types for copyToCode" on the line containing the function and "previous implicit declaration of copyToCode was here" warning on the line calling the function.
I have declared the variables:
char *code = malloc (32*1000* sizeof(char));
char *section1 = malloc(8*sizeof(char)), *section2 = malloc(8*sizeof(char));
I also tried this :
char *section1[8];
As a side question - which is correct?
The section1 and section2 are meant to be Strings, and the code is meant to be an array of strings.
Thanks for reading, I appreciate any help.
Gareth
You need to declare the function before you call it, otherwise the compiler will try to work out what the function prototype is on your behalf.
The message
previous implicit declaration of copyToCode
is telling you this. An implicit declaration is one that the compiler makes because you haven't yet given it an explicit declaration.
In your update to the question you say that code is intended to be an array of strings but you define it as:
char *code = malloc (32*1000* sizeof(char));
That allocates a single string. An array of strings would be held in a char**, just like argv. You would need to allocate the array first, which would contain n strings, each being a char*. Then you'd have to allocate each char* one by one in a loop.
This sort of coding is so much easier in C++ with the standard library string and vector classes.
This warning means that you have your declaration differs from the implementations. Or you have two different declarations of the function.
Because the warning is mentioning an implicit declaration it means that the declaration was deduced by gcc because you used the function before declaring it. GCC will use the parameters of the function call to deduce the declaration, which can lead to nasty problems.
If you declare the function, you will probably still get an error, but it should be much more specific.
Side note: If you are working with gcc, always compile as gcc -std=c99 -pedantic -Wall -Wextra -Wwrite-strings source.c
To your edit: Your variables are wrong. code is char * but your function takes char **.
Can you give us more detail about the variables you are using as parameters of the function?
Also worth to note is the fact that the first parameter of copyToCode is a pointer to a pointer of chars, what can be used as an array of strings.
The line:
void copyToCode (char **code, char *loc, char *data ){}
is the declaration of your function? In that case, you should write it as this:
void copyToCode (char **code, char *loc, char *data );
To define an array of strings, you'd need something like the following:
char **code;
int i;
code = malloc (32*sizeof(*code));
for (i=0; i<32; i++) {
code[i]=malloc(1000*sizeof(**code));
}
Note that this doesn't include error checking on the malloc results, which you should do. And it creates an array of size 32 containing strings of size 1000, which you shouldn't be hard coding.

"Incompatible pointer type" compiler warning for 4th argument of qsort

I'm trying to use the standard library's qsort to sort an array of wide characters:
wchar_t a = L'a';
wchar_t a1 = L'ä';
wchar_t b = L'z';
wchar_t chararray[] = {b, a, a1};
length = wcslen(chararray);
qsort(chararray, length, sizeof(wchar_t), wcscoll);
Now I think the functions involved have these prototypes:
int wcscoll(const wchar_t *ws1, const wchar_t *ws2);
void qsort(void *base, size_t num, size_t size, int (*comp_func)(const void *, const void *))
The results are completely as expected, but why am I getting the compiler warning "passing argument 4 of ‘qsort’ from incompatible pointer type"? And how can I cast wcscoll to fit the prototype?
The warning goes away if I define and pass in a separate comparison function:
int widecharcomp(const void *arg1, const void *arg2)
{
return wcscoll(arg1, arg2);
}
... but this one looks like it should have error handling for when the arguments are not of type wchar_t *.
You've done pretty much the right way. The gcc documentation for strcoll and wcscoll gives an example similar to this as the correct way to use strcoll or wcscoll with qsort.
/* This is the comparison function used with qsort. */
int
compare_elements (char **p1, char **p2)
{
return strcoll (*p1, *p2);
}
/* This is the entry point---the function to sort
strings using the locale's collating sequence. */
void
sort_strings (char **array, int nstrings)
{
/* Sort temp_array by comparing the strings. */
qsort (array, nstrings,
sizeof (char *), compare_elements);
}
This example actually does raise the warning that you want to get rid of, but again it can be gotten around by changing the char** to const void* in the arguments to compare_elements, and then explicitly casting to const char**.
You're right in observing that this is type-unsafe, but type safety is not exactly one of C's strong points. C doesn't have anything like generics or templates, so the only way that qsort can work on an arbitrary type is for its comparison function to accept void*s. It's up to the programmer to make sure that the comparison function is not used in a context where it may be passed arguments that are not the expected type.
That said, there is an error in your code. What the comparison function receives is not the elements to be compared, but rather pointers to the elements to be compared. So if the elements are strings, that means pointer-to-pointer. So when you write
return wcscoll(arg1, arg2);
You are actually passing wscoll a wchar_t** when it expects a wchar_t*. The correct way to do this, while suppressing the warning, would be:
int widecharcomp(const void *arg1, const void *arg2)
{
return wcscoll(*(const w_char_t**)arg1, *(const w_char_t**)arg2);
}
as ugly as that is.
Edit:
Just took another look at the top bit of your code. Your error is really twofold here. You're trying to use wcscoll to sort characters. It's a function meant to sort strings (which in C are pointers to nul-terminated sequences of characters). The above was written assuming you were trying to sort strings. If you want to sort characters, then wcscoll is not the appropriate function to use, but everything above regarding qsort still applies.
There are two problems: you've mixed up wchar_t and wchar_t*, and you've tried to pass off a wchar_t* as a void*.
First, you've told qsort to sort an array of wchar_t. But wcscoll doesn't compare wchar_t, it compares wide character strings which have the type wchar_t*. The fact that your comparison appears to have worked is due to your test data which just happens to work well under both interpretations.
If you wanted to sort characters, you need to call an appropriate function (I don't know the wide character API well enough to tell you which one). If you wanted to sort strings, you need to allocate an array of strings (of type wchar_t *).
Furthermore, even if you had an array of wchar_t*, you could not portably pass wcscoll as an argument to qsort. The issue is that there is no guarantee that wchar_t* and void* have the same representation. Some machines have word pointers that have a different representation from byte pointers; on such a machine, qsort would pass byte pointers to elements of the array to wcscoll, and this wouldn't work because wcscoll expects byte pointers. The solution is to write a trivial wrapper function that performs the conversion if necessary. A trivial wrapper is often necessary with qsort.
You've coded up your solution already (however, see other answers and edits at the end of this one about with the choice of the comparison function you're using and the data being passed to qsort()).
You could drop the wrapper function by casting the function pointer you pass to qsort() to the appropriate type, but I think using a wrapper is a better solution from a maintainability perspective. If you really want to avoid a wrapper function (maybe you're running into a measurable running into perf issue), you can cast like so:
qsort(chararray, length, sizeof(wchar_t), (int(*)(const void*,const void*))wcscoll);
Or make it arguably more readable using a typedef for the compare function type:
typedef
int (*comp_func_t)(const void *, const void *);
/* ... */
qsort(chararray, length, sizeof(wchar_t), (comp_func_t) wcscoll);
Unfortunately, the straight C qsort() can't be typesafe, so it can't have have "error handling for when the arguments are not of type wchar_t". You, the programmer, are responsible for ensuring that you're passing the correct data, sizes and comparison function to qsort().
Edit:
To address some of the problems mentioned in other answers about the types being passed ot the compare function, here's a routine that can be used to sort wchar_t using the current locale's collating sequence. The library might have something better, but I'm not aware of it at the moment:
int wchar_t_coll( const void* p1, const void* p2)
{
wchar_t s1[2] = {0};
wchar_t s2[2] = {0};
s1[0] = * (wchar_t*)p1;
s2[0] = * (wchar_t*)p2;
return wcscoll( s1, s2);
}
Also note, that the chararray you're passing to wcslen() isn't properly terminated - you'll need a 0 at the end of the initializer:
wchar_t chararray[] = {b, a, a1, 0};
You can't cast a function pointer to a different type, your current solution is as good it gets

Resources