Add numbers to filename - c

I want to store data in different files. Therefore I want to create files as follows: data_1.log, data_2.log, ..., data_N.log. The appendix .log is not necessary but would be nice. All my approaches failed so far. Here is one sample that is probably close to what I need:
#include <stdio.h>
#include <string.h>
char get_file_name(int k){
int i, j;
char s1[100] = "logs/data_";
char s2[100];
snprintf(s2, 100, "%d", k);
for(i = 0; s1[i] != '\0'; ++i);
for(j = 0; s2[j] != '\0'; ++j, ++i){
s1[i] = s2[j];
}
s1[i] = '\0';
return s1;
}
int main(){
char file_name[100];
for(int k=0; k<10; k++){
// Get data
// ...
// Create filename
strcpy(file_name, get_file_name(k));
printf("%s", file_name);
// fp = fopen(file_name, "w+");
// Write data to file
// print_results_to_file();
// fclose(fp);
}
return 0;
}
At the moment I get the following errors which I don't understand:
string.c: In function ‘get_file_name’:
string.c:14:12: warning: returning ‘char *’ from a function with return type ‘char’ makes integer from pointer without a cast [-Wint-conversion]
return s1;
^~
string.c:14:12: warning: function returns address of local variable [-Wreturn-local-addr]
string.c: In function ‘main’:
string.c:24:27: warning: passing argument 2 of ‘strcpy’ makes pointer from integer without a cast [-Wint-conversion]
strcpy(file_name, get_file_name(k));
^~~~~~~~~~~~~~~~
In file included from string.c:2:
/usr/include/string.h:121:14: note: expected ‘const char * restrict’ but argument is of type ‘char’
extern char *strcpy (char *__restrict __dest, const char *__restrict __src)
^~~~~~
Is there a more simpler way to create such filenames? I can't believe that there isn't one.

There are various issues with this code and rather than correcting them one by one here’s an alternative approach. It’s not the only one but it’s simple and should be easy to understand and adapt:
#include <stdio.h>
void get_file_name(int k, char* buffer, size_t buflen) {
snprintf(buffer, buflen, "logs/data_%d.log", k);
}
int main() {
const size_t BUFLEN = 50;
char file_name[BUFLEN];
for (int i = 0; i < 10; i++) {
get_file_name(i, file_name, BUFLEN);
printf("%s\n", file_name);
// Code for writing to file.
}
}
A few details:
Rather than attempting to return (pointers to) memory, this function passes a buffer that is written to. It’s up to the caller to ensure that the buffer is big enough (this is always the case here, but if the actual filenames are longer, you should add logic that inspects the return value of snprintf and performs appropriate error handling).
The actual logic of the function requires only a single call to snprintf, which already performs everything you require, so it’s unclear whether having a separate function is even necessary or helpful.
The above uses variable-length arrays. If you want to ensure constant buffers, you can use a #define instead of a const size_t variable for the buffer length. However, using a variable-length array here is fine, and some compilers even convert it into a constant array.
As mentioned in comments, it’s important that you (a) read and understand the documentation of the functions you’re using, and (b) read and understand the compiler error messages.

The function get_file_name has return type char
char get_file_name(int k){
but it returns an object of type char *
char s1[100] = "logs/data_";
//...
return s1;
Moreover the returned pointer points to a local array s1 that will not alive after exiting the function.
In this call
strcpy(file_name, get_file_name(k));
the type of the second argument (that is char according to the function get_file_name declaration) shall be char *.
There is neither the function print_results_to_file declaration nor its definition.
According to the C Standard the function main without parameters shall be declared like
int main( void )
I would write the function get_file_name the following way
#include <stdio.h>
#include <string.h>
char * get_file_name( char *file_name, size_t n, size_t padding )
{
const char *common_part = "logs/data_";
snprintf( file_name, n, "%s%zu", common_part, padding );
return file_name;
}
int main( void )
{
enum { N = 100 };
char file_name[N];
for ( size_t i = 0; i < 10; i++ ) puts( get_file_name( file_name, N, i ) );
}
The program output is
logs/data_0
logs/data_1
logs/data_2
logs/data_3
logs/data_4
logs/data_5
logs/data_6
logs/data_7
logs/data_8
logs/data_9

There are several problems with your code, but the biggest one is that you are trying to return a pointer to a local variable from get_file_name.
This is a big no no since the memory allocated for char s1[100] in get_file_name is freed immediately after return.
The rest of the errors are because you forgot the * in char get_file_name(int k).
There are several possible solutions:
Pass in a char array for the function to fill.
Use a global variable (This is considered a bad practice).
Dynamically allocate the memory.
Make the local variable static (this is a bit hacky, but legal)

Your errors are easily explained:
get_file_name should return a char but you create a char[] and return this(it isthe same as char*)
get_file_name returns the adress of an array that is created in the function itself. After the function ends, the array may be overwritten. Add the array as parameter or use malloc
strcpy does not work because it expects a char* (char[]) and not a char. get_file_name returns a char.
print_results_to_file is not defined. You may need to include other files you use in the program (e.g. if the function is implemented in a file func.c the prototype should be in a file called func.h that is included via #include "func.h".

Related

error: implicit declaration of function ‘memcpy_s’; did you mean ‘memcpy’? [-Werror=implicit-function-declaration]

I am trying to make a memcpy_s() call. Below is my code snippet where I am observing warning
" error: implicit declaration of function ‘memcpy_s’; did you mean ‘memcpy’? [-Werror=implicit-function-declaration]"
#include <stdio.h>
#include <string.h>
#include <stdint.h>
static const uint32_t ab[10] = {0,1,2,3,4,5,6,7,8,9};
void main()
{
uint32_t u[10];
memcpy_s((void *)&u[0], sizeof(u), (void *)&ab[0], 10 * sizeof(uint32_t));
}
It appears that the IDE/Platform you are using doesn't support the memcpy_s() variant of memcpy, which IMO is good!
I'd recommend using memcpy() instead.
If you haven't already used it before --
Looking at the reference page for memcpy
void *memcpy(void *restrict dest, const void *restrict src, size_t n);
It needs the following arguments:
dest - pointer to the object to copy to
src - pointer to the object to copy from
n - number of bytes to copy
So,
memcpy((void*)&u[0], (void*)&ab[0], 10*sizeof(uint32_t));
Or better,
memcpy((void*)&u[0], (void*)&ab[0], COUNT_OF(ab)*sizeof(uint32_t));
// ↑ Note this!
with a minimalistic, not-so-perfect macro to get count of elements in the array:
#define COUNT_OF(var) (sizeof(var)/sizeof(var[0]))
By the way, there is a typo in your code:
memcpy_s(void *)&u[0], sizeof(u), (void*)&ab[0], 10*sizeof(uint32_t));
// ↑ ↑ ouch!
is the parenthesis. If you at all migrate to a platform where you have memcpy_s() supported then change it to:
memcpy_s((void*)&u[0], sizeof(u), (void*)&ab[0], COUNT_OF(ab)*sizeof(uint32_t));
Update:
I learnt from OP that the actual assignment is to write a function which behaves like memcpy().
Assuming the nature of arguments to remain consistent with what memcpy() needs, adding a return to indicate if the copy happened successfully, you can of course add more.
A bare-minimum, simple version can be programmed as:
int my_memcpy(void *pDest, void *pSrc, size_t sz)
{
char *src = (char *)pSrc; // Or use uint8_t instead of char
char *dest = (char *)pDest; // Or use uint8_t instead of char
// Validate pointers to avoid seg-faults
if(NULL == pDest || NULL == pSrc) {
return -1;
}
// Copy contents
for (int i = 0; i < sz; i++) {
dest[i] = src[i];
}
return 0;
}

C sort array of strings with qsort and strcmp - warning: incompatible pointer type

I tried to sort an array of strings with qsort but got this warning:
warning: passing argument 4 of 'qsort' from incompatible pointer type
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX_PRODUCTS 1000
int main (void) {
int i, index = 0, isUnique;
char products[MAX_PRODUCTS][100];
char product[100];
int count[MAX_PRODUCTS];
FILE * fp;
fp = fopen ("one.txt", "r");
// Read words from file and put in array if unique
while (fscanf(fp, "%s", product) != EOF){
isUnique = 1;
for (i=0; i<index && isUnique; i++){
if (strcmp(products[i], product) == 0){
isUnique = 0;
}
}
if (isUnique) {
strcpy(products[index], product);
index++;
}
else {
count[i - 1]++;
}
}
qsort(products, MAX_PRODUCTS, sizeof(char*), strcmp);
fclose(fp);
return 0;
}
I also tried a custom function to compare strings but this didn't worked either.
What can I do to fix it?
qsort is documented on the Microsoft website where it states:
compare
Pointer to a user-supplied routine that compares two array elements and returns a value that specifies their relationship.
Use this:
int compare (const void * a, const void * b)
{
return strcmp((char*)a, (char*)b );
}
the following way:
qsort(products, MAX_PRODUCTS, 100, compare);
You tell qsort(), that you want to sort an array of pointers, but have indeed an array of arrays!
This gives you an array of pointers:
char *products[MAX_PRODUCTS]
for (int i = 0; i < sizeof(products)/sizeof(*products); i++) {
products[i] = malloc(100);
}
You could also sort the whole array members, but this involves swapping the whole strings (strictly spoken, the whole arrays, even if the strings are shorter) a multitude of times, which can be quite inefficient. It is much faster to only swap the pointers.
Furthermore, the signature of strcmp() does not match the prototype, that qsort expects. So you should wrap it in a compare-function with prototype
int compar(const void *, const void *);
as shown in the manpage.
Then, the compiler should not complain any more.
You actually have more problems than the warning you get:
You always sort MAX_PRODUCTS elements of the products array, no matter how many elements are actually valid (you sort uninitialized and indeterminate strings).
You say that the element-size of the products array is sizeof(char*), but products is an array of arrays, so each element of products is sizeof producst[0] large.
Now for the warning itself: The declaration of strcmp is
int strcmp( const char *lhs, const char *rhs );
while the comparison function passed to qsort is
int (*comp)(const void *, const void *)
The argument types are different. A seemingly possible solution is to cast the strcmp pointer to the correct type:
typedef int (*sortfun_type)(const void *, const void *);
// After the loop the variable index should be the number of strings read
qsort(products, index, sizeof products[0], (sortfun_type) &strcmp);
As noted in a comment, this is technically not correct (but should work anyway). The proper solution is to write a wrapper-function with the correct arguments types, which then calls strcmp (as shown by others).

Error : format'%s' expects argument of type 'char *', but argument 2 has type 'int' [-Wformat=]

I am currently trying to do my own shell, and it has to be polyglot.
So I tryed to implement a function that reads the lines in a .txt file.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// globals
char lang[16] = {'t','r','y'};
char aMsg[512];
// functions
void takeFile() {
int i =0;
char namFil[32];
char lg[16];
FILE * file;
char tmp[255];
char * line = tmp;
size_t len = 0;
ssize_t read;
strcpy(namFil,"/media/sf_Projet_C/");
strcpy(lg,lang);
strcat(lg, ".txt");
strcat(namFil, lg);
file = fopen(namFil, "r");
printf("%s\n", namFil);
while((read = getline(&line,&len, file)) != -1) {
aMsg[i] = *line;
i++;
}
}
enum nMsg {HI, QUIT};
int main(void) {
takeFile();
printf("%s\n%s\n", aMsg[HI], aMsg[QUIT]);
}
I am on win7 but I compile with gcc on a VM.
I have a warning saying :
format'%s' expects argument of type 'char *', but argument 2 (and 3) has type 'int' [-Wformat=]
I tried to execute the prog with %d instead of %s and it prints numbers.
I don't understand what converts my aMsg into a int.
My try.txt file is just :
Hi
Quit
The contents of your text file have nothing to do with the warning, which is generated by the compiler before your program ever runs. It is complaining about this statement:
printf("%s\n%s\n", aMsg[HI], aMsg[QUIT]);
Global variable aMsg is an array of char, so aMsg[HI] designates a single char. In this context its value is promoted to int before being passed to printf(). The %s field descriptor expects an argument of type char *, however, and GCC is smart enough to recognize that what you are passing is incompatible.
Perhaps you had in mind
printf("%s\n%s\n", &aMsg[HI], &aMsg[QUIT]);
or the even the equivalent
printf("%s\n%s\n", aMsg + HI, aMsg + QUIT);
but though those are valid, I suspect they won't produce the result you actually want. In particular, given the input data you specified and the rest of your program, I would expect the output to be
HQ
Q
If you wanted to read in and echo back the whole contents of the input file then you need an altogether different approach to both reading in and writing out the data.
Let's take a closer look on the problematic line:
printf("%s\n%s\n", aMsg[HI], aMsg[QUIT]);
The string you would like to print expects 2 string parameters. You have aMsg[HI] and aMsg[QUIT]. These two are pointing to a char, so the result is one character for each. All char variables can be interpreted as a character or as a number - the character's ID number. So I assume the compiler resolves these as int types, thus providing you that error message.
As one solution you merely use %c instead of %s.
However, I suspect you want to achieve something else.
I'm completely guessing, but I think what you want is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// globals
char lang[16] = {'t','r','y'};
char *aMsg[512];
// functions
void takeFile() {
int i =0;
char namFil[32];
char lg[16];
FILE * file;
char tmp[255];
char * line = tmp;
size_t len = 0;
ssize_t read;
strcpy(namFil,"/media/sf_Projet_C/");
strcpy(lg,lang);
strcat(lg, ".txt");
strcat(namFil, lg);
file = fopen(namFil, "r");
printf("%s\n", namFil);
while((read = getline(&line,&len, file)) != -1) {
aMsg[i] = malloc(strlen(line)+1);
strcpy(aMsg[i], line);
i++;
}
fclose(file);
}
enum nMsg {HI, QUIT};
int main(void) {
takeFile();
printf("%s\n%s\n", aMsg[HI], aMsg[QUIT]);
free(aMsg[HI]);
free(aMsg[QUIT]);
return 0;
}

Cannot return and assign char array to pointer in C

char *test = "hello";
test = change_test("world");
printf("%s",test);
char* change_test(char *n){
printf("change: %s",n);
return n;
}
im trying to pass a 'string' back to a char pointer using a function but get the following error:
assignment makes pointer from integer without a cast
what am i doing wrong?
A function used without forward declaration will be considered having signature int (...). You should either forward-declare it:
char* change_test(char*);
...
char* test = "hello";
// etc.
or just move the definition change_test before where you call it.
printf() prints the text to the console but does not change n. Use this code instead:
char *change_test(char *n) {
char *result = new char[256];
sprintf(result, "change: %s", n);
return result;
}
// Do not forget to call delete[] on the value returned from change_test
Also add the declaration of change_test() before calling it:
char *change_test(char *n);
You're converting an integer to a pointer somewhere. Your code is incomplete, but at a guess I'd say it's that you're not defining change_test() before you use it, so the C compiler guesses at its type (and assumes it returns an integer.) Declare change_test() before calling it, like so:
char *change_test(char *n);
thanks a bunch guys! didnt think i would have this problem solved by lunch. here is the final test class
/* standard libraries */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* change_test(char*);
int main(){
char *test = "hello";
test = change_test("world");
printf("%s",test);
return (EXIT_SUCCESS);
}
char* change_test(char *n){
return n;
}

correct format for function prototype

I'm writing to a text file using the following declaration:
void create_out_file(char file_name[],long double *z1){
FILE *out;
int i;
if((out = fopen(file_name, "w+")) == NULL){
fprintf(stderr, "***> Open error on output file %s", file_name);
exit(-1);
}
for(i = 0; i < ARRAY_SIZE; i++)
fprintf(out, "%.16Le\n", z1[i]);
fclose(out);
}
Where z1 is an long double array of length ARRAY_SIZE. The calling function is:
create_out_file("E:/first67/jz1.txt", z1);
I defined the prototype as:
void create_out_file(char file_name[], long double z1[]);
which I'm putting before "int main" but after the preprocessor directives. My code works fine.
I was thinking of putting the prototype as
void create_out_file(char file_name[],long double *z1).
Is this correct? *z1 will point to the first array element of z1.
Is my declaration and prototype good programming practice?
Thanks a lot...
Update: To make the program general, I defined ARRAY_SiZE as:
const int ARRAY_SIZE = 11;
The prototype becomes:
void create_out_file(const char *file_name, const long double *z1, size_t z_size)
the called function is:
create_out_file("/tmp/myname", z1, ARRAY_SIZE);
and in the function declaration I have
void create_out_file(const char *file_name, const long double *z1, size_t z_size)
FILE *out;
int i;
if((out = fopen(file_name, "w+")) == NULL){
fprintf(stderr, "***> Open error on output file %s", file_name);
exit(-1);
}
for(i = 0; i < z_size; i++)
fprintf(out, "%.16Le\n", z1[i]);
fclose(out);
}
Will this work?
New Update On compilation, for the line
for(i = 0; i < z_size; i++)
in the declaration, I get the warning: : warning C4018: '<' : signed/unsigned mismatch
What's wrong here?
Thanks...
Latest news: It's working fine thanks to Jonathan Leffler
Use 'const char file_name[]' or 'const char *file_name' - you aren't going to change the name in the function.
Likewise, use 'const long double *z1' or 'const long double z1[]'.
The choice between pointer and array notation in a function prototype is largely arbitrary. I almost always use the pointer notation - because ultimately that is what is passed into the function. There are those who argue that if you are going to use the pointer as an array, use the array notation; it is a perfectly reasonable viewpoint - but not the one I use.
Your code is more general if you pass the array size into the function:
void create_out_file(const char *file_name, const long double *z1, size_t z_size)
{
...
}
Note that the choice between pointer and array notation is not arbitrary for global variables. There is a lot of difference between these two:
extern char *something;
extern char anotherthing[];
One says there is a pointer-sized memory location that contains the address of a character string (presumably). The other says that there is a character string somewhere known by the name 'anotherthing', the value of which is a pointer. That may be a bit subtle - but the difference is crucial. The 'pointer == array' isomorphism only applies in function argument lists.
declarations: long double z1[] and long double *z1 are completely same.
*z1 will point to the first array element of z1
yes. there is no such entity array in c. There are only pointers and some thin syntax sugar for accessing them [ ].

Resources