snprintf in a loop does not work on linux - c

snprintf in a loop does not work on linux but it works properly on windows.
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char **argv) {
char buffer[255] ={0};
for ( int i = 0; i < 10; i++) {
snprintf(buffer, 255, "%s:%x\0",buffer, i );
}
printf ( "BUFFER = %s\n", buffer );
return 0;
}
This code does not append existing buffer but only takes the last iteration value.

You can avoid the undefined behavior of using the buffer both as the target string and as an argument like this:
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char **argv) {
char buffer[255] ={0};
int offset = 0;
for ( int i = 0; i < 10; i++) {
offset += snprintf(buffer + offset, 255 - offset, ":%x\0", i);
}
printf ( "BUFFER = %s\n", buffer );
return 0;
}

sprintf()'ing the result array to itself is undefined behaviour.
EDIT: if you want some code that works, here you are: use strcat() (or the safer strncat, etc. insert usual security discussion about buffer overflow here):
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char **argv) {
char buffer[255] = { 0 };
char fmtbuf[64];
int i;
for (i = 0; i < 10; i++) {
snprintf(fmtbuf, 64, "%x", fmtbuf, i);
strcat(buffer, fmtbuf);
}
printf ("BUFFER = %s\n", buffer);
return 0;
}
Also note that printf() calls don't need the terminating zero to be written out manually -- it's automatically added.

snprintf does work as specified on Linux, but your code does not append it. Read the Note in the linked documentation!
You should not use as its arguments (after the format string) the destination.
If you want it to append, either ensure that you don't overflow your fixed buffer, or reallocate that buffer when it gets too small.

You could not write 'buffer' to itself by 'snprintf'.
The test code is as follow:
#include <stdio.h>
#include <stdlib.h>
#include <cstring>
int main( int argc, char **argv) {
char buffer[255] ={0};
for ( int i = 0; i < 10; i++) {
char tmp[255] = {0};
strcpy(tmp, buffer);
snprintf(buffer, 255, "%s:%x\0",tmp, i );
printf ( "BUFFER = %s\n", buffer );
}
printf ( "BUFFER = %s\n", buffer );
return 0;
}

The standard specifically states that this code is not expected to work. Firstly, the initial buffer argument is declared restrict, which means that it cannot alias another argument. Secondly, the standard has the following clause just for emphasis:
c99
7.19.6.5 The snprintf function
Description
2 - [...] If copying takes place between objects that overlap, the behavior is undefined.

Related

How to allocate a dynamic memory zone for a character string in C

Why doesn't this code work? What I have been trying to do is make a dynamic allocation for an unknown user input length of an array using int main(int ac, char ** ac) and malloc().
#include <stdio.h>
#include <stdlib.h>
int main(int ac, char **av)
{
char *str;
int i;
str = malloc(sizeof(char) * (ac + 1));
i = 0;
if(str[i] != '\0')
{
i = i + 1;
printf("%s\n\t", str);
}
return(0);
}
Name the parameters of main() in the standardized way: int argc, char *argv[].
(note that argv[0] is the name of the executable, which may or may not be of interest to you)
First you need to allocate argc number of pointers to character. Optionally with a NULL sentinel value at the end if that makes sense for your program - don't confuse this with null termination though.
So you should rather have something like char** str_table = malloc(sizeof(*str_table) * argc);
For each item in str_table, allocate additional memory for strlen(argv[i]) + 1 characters, the actual data. In this case the +1 is for null termination and it is mandatory.
strcpy from argv[i] to your own array.
ac is not the length of any argument, but rather the argument count.
When the user specifies one argument this will always be 2.
If the program should only output the first argument you can just do:
#include <stdio.h>
int main(int argc, char **argv) {
if(argc == 2)
printf("%s\n", argv[1]);
return 0;
}
If you want to load the argument into a string you have to get it's length.
This can for example be done with the strlen() function:
#include <stdio.h> /* for printf */
#include <stdlib.h> /* for malloc and free */
#include <string.h> /* for strlen and strcpy */
int main(int argc, char **argv) {
if(argc == 2) {
char *input_string;
int input_string_length;
input_string_length = strlen(argv[1]);
/* strlen() does not include the '\0' in the length */
input_string = malloc((input_string_length + 1) * sizeof(char));
strcpy(input_string, argv[1]);
printf("%s\n", input_string);
free(input_string);
}
return 0;
}
ac doesn't represent user input length (as you have been trying to allocate memory for ac+1) + str points to a raw memory location without any valid data, even then if you want to go with ac then:
#include <stdio.h>
#include <stdlib.h>
#include <string.h> //added for memset
int main(int ac, char **av)
{
char *str;
int i; //USELESS
str = malloc(sizeof(char) * (ac + 1)); //str points to a memory (if allocated) which contains garbage
i = 0; //NO USE
if(str) //checks if memory has been allocated - NO INCREMENT NEEDED OR VALID
{
printf("Memory has been successfully allocated");
memset(str,'\0',ac+1); //added for NULL termination
}
return(0);
}
In case you are trying to allocate memory on the stack, you may also look for VLA.
This statement
str = malloc(sizeof(char) * (ac + 1));
does not make sense.
Moreover the allocated array was not initialized. So this statement
if(str[i] != '\0')
results in undefined behavior.
It seems what you are trying to do is to output command line parameters by copying them in dynamically allocated arrays.
If so then the program can look the following way
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main( int argc, char * argv[] )
{
if ( argc > 1 )
{
char **s = malloc( ( argc - 1 ) * sizeof( char *) );
for ( int i = 0; i < argc - 1; i++ )
{
s[i] = malloc( strlen( argv[i+1] ) + 1 );
strcpy( s[i], argv[i+1] );
}
for ( int i = 0; i < argc - 1; i++ )
{
puts( s[i] );
}
for ( int i = 0; i < argc - 1; i++ ) free( s[i] );
free( s );
}
return 0;
}
If to run the program like for example
program Hello World
then the output will be
Hello
World
You can add yourself checks to the program that the memory allocations were successful.
There are some logic error in your code.
int ac is the number of arguments.
char **av contain the arguments.
For example : ./program arg1 arg2
av[0] is gonna be "./program"
av[1] is gonna be "arg1"
av[2] is gonna be "arg2"
av[2][0] is gonna be "a"
Now if you just want the size of the first argument you can use strlen() :
int size = strlen(av[1]);
What you need instead of your if statement is a while loop to go throught all the elements of av.
For example :
int i = 0;
while (i <= ac) {
printf("%s", av[i]);
...Your code...
i++;
}

Convert an array of command line arguments and store them in an int array

I am writing a program that takes an argument array from the command line(ex. 10 20 30 40), converts them into integers and saves them in an int array to be used later. I have declared a pointer for the heap. I want to store the number count from the CL in the length variable. Then allocate space for the length and copy it to the heap. Next, use a function that converts the command line arguments to an integer and copy them in a int array.I am confused as to how I can pass the command line values. Could someone point me in the right direction? Thanks.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
void convert(char** source, int length);
int main(int argc, char *argv[]){
int length = 0;
char *p_heap;
if( argc > 11 || argc < 2 ) {
printf("arguments 1-10 are accepted %d provided\n", argc-1);
printf("Program Name Is: %s",argv[0]);
exit(EXIT_FAILURE);
}
length = argc-1;
p_heap = malloc(sizeof(length));
strcpy(p_heap, length);
convert(p_heap, length);
//printf("Average %f\n", avg());
puts(p_heap);
free(p_heap);
return 0;
}
void convert(char** source, int length){
int *dst;
int i;
for(i=0;i<length;i++) {
dst = atoi([i]);
}
}
Note: I am assuming correct input from CL.
I want to store the number count from the CL in the length variable.
If you assume correct input from CL, then you have this number in argc-1.
Then allocate space for the length and copy it to the heap.
dst = malloc((argc-1)*sizeof *dst);
Next, use a function that converts the command line arguments to an integer and copy them in a int array.
for(int i=0; i<argc-1; i++)
sscanf(source[i], "%d", &dst[i]);
You should also change the return type of convert to int * and then return dst.
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
int main(int argc, char **argv)
{
if (argc == 1)
return EXIT_SUCCESS;
long *data = malloc((argc - 1) * sizeof *data);
for (int i = 1; i < argc; ++i) {
char *endptr;
errno = 0;
data[i-1] = strtol(argv[i], &endptr, 10);
if (*endptr != '\0') {
fputs("Input error :(", stderr);
return EXIT_FAILURE;
}
if (errno == ERANGE) {
fputs("Parameter out of range :(\n\n", stderr);
return EXIT_FAILURE;
}
}
for (int i = 0; i < argc - 1; ++i)
printf("%ld\n", data[i]);
free(data);
}
why the comparison with 11 in if( argc > 11 || argc < 2 ) { ?
in
length = argc-1;
p_heap = malloc(sizeof(length));
sizeof(length) is sizeof(int) and does not depend on the value of length if it was your hope
In
strcpy(p_heap, length);
strcpy get two char*, length values the number of args rather than the address of an array of char, so the result is undefined and probably dramatic
In
convert(p_heap, length);
the first argument of convert must be a char** but p_heap is a char*
in
void convert(char** source, int length){
int *dst;
int i;
for(i=0;i<length;i++) {
dst = atoi([i]);
}
}
you do not use source
dst is a int* while atoi return an int
[i] ???
Before to give code on S.O. I encourage you to check first it compile without warning/error, using high warning level (e.g. gcc -pedantic -Wextra for gcc )

How to format and merge strings

I am trying to format and merge the strings (with sprintf) and then print them with printf. But it does not work, and I have no clue why.
The error is that string is not initialised.
int main() {
char wochentag[] = "Freitag";
int tag = 13;
char monat[] = "Mai";
int jahr = 1927;
char *string;
char *array=(char *) malloc(26*sizeof(char));
sprintf (string,"%s" "%d" "%s" "%d",wochentag,tag,monat,jahr);
printf("%s\n", string);
free(array);
return 0;
}
The following fixes achieve what you're trying to do:
char *array=(char *) malloc(26*sizeof(char));
A pointer to char is char*, not *char.
char *array=(char *) malloc(26*sizeof(char));
sprintf (array,"%s %d %s",wochentag,tag,monat);
printf("%s\n", array);
Since you allocate memory to your array variable, that's what you should use in sprintf and printf, right? Also note that the correct use of sprintf is with quotation marks.
This is the fixed code:
int main() {
char wochentag[] = "Freitag";
int tag = 13;
char monat[] = "Mai";
int jahr = 1927;
char *string;
char *array=(char *) malloc(26*sizeof(char));
sprintf (array,"%s %d %s",wochentag,tag,monat);
printf("%s\n", array);
free(array);
return 0;
}
the following code compiles cleanly, removes code clutter, performs error checking, includes the needed header files, is appropriately indented for readability and works correctly.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char wochentag[] = "Freitag";
int tag = 13;
char monat[] = "Mai";
int jahr = 1927;
char *string=malloc(26);
if( NULL == string)
{ // then malloc failed
perror( "malloc for 26 bytes failed");
exit( EXIT_FAILURE);
}
// implied else, malloc successful
sprintf (string,"%s%d%s%d",wochentag,tag,monat,jahr);
printf("%s\n", string);
free(string);
return 0;
}

How to read a line from a read-only FIFO in C?

I've got a problem reading a couple of lines from a read-only FIFO. In particular, I have to read two lines — a number n, followed by a \n and a string str — and my C program should write str in a write-only FIFO for n times. This is my attempt.
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
char *readline(int fd);
int main(int argc, char** argv) {
int in = open(argv[1], O_RDONLY);
mkfifo(argv[2], 0666);
int out = open(argv[2] ,O_WRONLY);
char *line = (char *) malloc(50);
int n;
while (1) {
sscanf(readline(in), "%d", &n);
strcpy(line, readline(in));
int i;
for (i = 0; i < n; i++) {
write(out, line, strlen(line));
write(out, "\n", 1);
}
}
close(in);
close(out);
return 0;
}
char *readline(int fd) {
char *c = (char *) malloc(1);
char line[50];
while (read(fd, c, 1) != 0) {
if (strcmp(c, "\n") == 0) {
break;
}
strcat(line, c);
}
return line;
}
The code is working properly, but it puts a random number of newlines after the last string repetition. Also, this number changes at each execution.
Could someone please give me any help?
Besides the facts that reading character wise and and comparing two characters using "string" comparsion both is far from being efficient, readline() returns a pointer to memory being declared local to readline(), that is line[50] The memory gets deallocated as soon as readline() returns, so accessing it afterwards invokes undefine behaviour.
One possibility to fix this is to declare the buffer to read the line into outside readline() and pass a reference to it down like so:
char * readline(int fd, char * line, size_t size)
{
if ((NULL != line) && (0 < size))
{
char c = 0;
size_t i = 0;
while (read(fd, &c, 1) >0)
{
if ('\n' == c) or (size < i) {
break;
}
line[i] = c;
++i;
}
line [i] = 0;
}
return line;
}
And then call it like this:
char * readline(int fd, char * line, size_t size);
int main(void)
{
...
char line[50] = "";
...
... readline(in, line, sizeof(line) - 1) ...
I have not tried running your code, but in your readline function you have not terminated the line with null ('\0') character. once you hit '\n' character you just breaking the while loop and returning the string line. Try adding '\0' character before returning from the function readline.
Click here for more info.
Your code did not work on my machine, and I'd say you're lucky to get any meaningful results at all.
Here are some problems to consider:
readline returns a locally defined static char buffer (line), which will be destroyed when the function ends and the memory it once occupied will be free to be overwritten by other operations.
If line was not set to null bytes on allocation, strcat would treat its garbage values as characters, and could possibly try to write after its end.
You allocate a 1-byte buffer (c), I suspect, just because you need a char* in read. This is unnecessary (see the code below). What's worse, you do not deallocate it before readline exits, and so it leaks memory.
The while(1) loop would re-read the file and re-print it to the output fifo until the end of time.
You're using some "heavy artillery" - namely, strcat and memory allocation - where there are simpler approaches.
Last, some C standard versions may require that you declare all your variables before using them. See this question.
And here's how I modified your code. Note that, if the second line is longer than 50 characters, this code may also not behave well. There are techniques around the buffer limit, but I don't use any in this example:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
char *readline(int fd, char * buffer);
int main(int argc, char** argv) {
int in = open(argv[1], O_RDONLY);
int out;
int n;
int i;
char line[50];
memset(line, 0, 50);
mkfifo(argv[2], 0666);
out = open(argv[2] ,O_WRONLY);
sscanf(readline(in, line), "%d", &n);
strcpy(line, readline(in, line));
for (i = 0; i < n; i++) {
write(out, line, strlen(line));
write(out, "\n", 1);
}
close(in);
close(out);
return 0;
}
char *readline(int fd, char * buffer) {
char c;
int counter = 0;
while (read(fd, &c, 1) != 0) {
if (c == '\n') {
break;
}
buffer[counter++] = c;
}
return buffer;
}
This works on my box as you described. Compiled with GCC 4.8.2 .

Printing a C string in reverse without using pointers?

Is there a way to print a string of fixed size in reverse without using pointers?
#include<stdio.h>
main()
{
char buffer[10];
scanf("%s", buffer);
// need to print buffer in reverse without using pointers??
}
A lovely K&R function to reverse your string in-place before printing it, perhaps?
#include <stdio.h>
#include <string.h>
void strrev(char *s) {
int tmp, i, j;
for (i = 0, j = strlen(s) - 1; i < j; i++, j--) {
tmp = s[i];
s[i] = s[j];
s[j] = tmp;
}
}
int main(int argc, const char *argv[]) {
char buffer[10];
scanf("%s", buffer);
strrev(buffer);
printf("%s\n", buffer);
return 0;
}
#include<stdio.h>
main()
{
char buffer[10];
int n = scanf("%s", buffer);
// print the number of chars written to buffer
if (n != EOF) {
int len = strlen(buffer);
if (len <= 10) {
int i;
for (i = len - 1; i >= 0; i--)
printf("%c", buffer[i]);
}
}
}
Since [] is just syntactic sugar for pointers, here's a version that works completely without pointers, arrays or anything else, just one single int. You didn't say that the string has to be stored somehow. :) (Note that I use fgetc instead of a buffer and scanf).
[jkramer/sgi5k:.../c]# cat rev.c
#include <stdio.h>
#include <stdlib.h>
void read_print();
int main(void) {
fputs("Enter your string, yo! ", stdout);
read_print();
fputs("\nDone!\n", stdout);
return EXIT_SUCCESS;
}
void read_print() {
int c = fgetc(stdin);
if(c != EOF && c != '\n') {
read_print();
fputc(c, stdout);
}
}
[jkramer/sgi5k:.../c]# gcc -o rev rev.c -Wall -W -Os
[jkramer/sgi5k:.../c]# ./rev
Enter your string, yo! foobar
raboof
Done!
Here's a recursive way of doing it; technically, this is using a pointer, but I wouldn't go into language-lawyer mode with such simple tasks.
#include <stdio.h>
/* If you want it printed forward, or backward, or think of another way.. */
typedef enum {
FRONT = 1,
BACK,
} direction;
/* Technically still using a pointer...don't nitpick. */
void echo_string(char buffer[], size_t buflen, direction from)
{
/* An index into the buffer to echo, which will preserve
* its value across subsequent recursive calls.
*/
static size_t index = 0;
/* According to the specified direction, print from the front
* or the back of the buffer. Advance the index (a misnomer, I guess).
*/
if(from == FRONT) {
printf("%c", buffer[index++]);
}
else {
printf("%c", buffer[buflen - ++index]);
}
/* Are there any more characters to echo? Yes? Awesome! */
if(index != buflen) {
echo_string(buffer, buflen, from);
}
}
int main(int argc, char **argv)
{
char buffer[10];
scanf("%s", buffer);
/* Better strlen() than sizeof() here,
* but BEWARE! scanf() is DANGEROUS!
*/
echo_string(buffer, strlen(buffer), BACK);
return(0);
}
reverse(char c[], int len)
{
if( ! (len / 2))
return;
char t = c[0];
c[0] = c[len--];
c[len] = t;
reverse(c, len-1);
}
The error(s) is left as an exercise to the student.
As caf pointed out, we're still using pointers..!
Here's an other way to solve the problem (of reversing a string).
This code snippet (and probably most others) don't respect stuff like utf8. I think signines post demonstrating the K&R way was quite close to mine (:D) so I adapted mine to fit that example (and corrected some things..)
#include <stdio.h>
#include <string.h>
void strrev(char *s) {
size_t len = strlen(s) + 1;
size_t i, j;
for(i = 0; i < len / 2; i++) {
j = len-1 - i-1;
char tmp = s[j];
s[j] = s[i];
s[i] = tmp;
}
}
int main(int argc, const char *argv[]) {
char buffer[10];
scanf("%s", buffer); // Look out for an overflow ;)
strrev(buffer);
puts(buffer);
return(0);
}
You can use strrev to reverse a string.
#include <stdio.h>
#include <string.h>
main()
{
char buffer[10];
scanf("%s", buffer);
strrev(buffer);
printf("%s", buffer);
}
void outstrreverse(const char s[])
{
size_t l=strlen(s);
while( l && s!=&s[--l] )
putchar(s[l]);
if(s[0])
putchar(s[0]);
}
Because of the relationship between C strings, arrays, and pointers the exercise is rather shotty IMHO - the most idiomatic description of a "String" in C is represented by the char*, which is not an array. Your (the OPs) title and post differ in their definitions between string and char[fixed length].
The OP should read and understand this FAQ entry, and between that and the posts here: easily figure out a solution—as well as defend it to the teacher/judge if need be.
I'll comment on this: never use scanf("%s", buffer) to populate a fixed length string. If you must use scanf() to do it, please use a field width specifier: e.g. scanf("%9s", buffer); if buffer is an [10], you want a specifier of 9 because of how scanf fills the buffer: otherwise you must beware the dragons! You could also scanf by character and evade the issue with a loops bounds, but that would likely be less efficient.
#include <stdio.h>
#include <conio.h>
void reverse(char a[], int s, int sc );
void reverse(char a[], int s, int sc ){
if ((sc-s)<(s-1))
{
a[sc-s]^=a[s-1];
a[s-1]^=a[sc-s];
a[sc-s]^=a[s-1];
reverse (a, s-1, sc) ;
}
}
void main (){
char a[]="ABCDEFG";
reverse(a, 7, 7);
printf("%d",a);
getch(); //i just use it to freeze the screen
}

Resources