I am writing a c library but before I want to test the functions. So, I do the following:
int main(void)
{
GString *msg = NULL;
msg = g_string_sized_new(256);
printf ("Insert a string (255 characters at most): ");
do_fgets((char *) msg->str, (size_t) msg->len, stdin);
printf("msg->allocated_len = %u \n", (size_t) msg->allocated_len);
printf("msg->len = %u \n", (size_t) msg->len);
return 0;
}
the compile is ok, but the program prints the following:
msg->allocated_len = 512
msg->len = 0
Why this? Is there any other way to get interactive input from the user using glib functions?
I'll be grateful if somebody could help me!
I'm assuming the do_fgets is your own function wrapping fgets, anyway...
Your code is failing since it is trying to read 0 bytes (the initial value of msg->len). Additionally, msg->len is never updated (it is passed to do_fgets by value).
Resurection!
I think I've found the solution to my question. What I did is to read the input to a buffer and then assign the buffer to the struct member src an everything is ok. That's the code roughly:
int main(void)
{
GString *msg = NULL;
gchar *p;
gchar buf[256];
msg = g_string_sized_new(256);
printf ("Enter a message (255 characters at most): ");
p = fgets(buf, sizeof(buf), stdin);
g_string_assign(msg, buf);
printf("msg->str = [%s] \n", (char *) msg->str);
printf("msg->len = %u \n", (size_t) msg->len);
printf("msg->allocated_len = %u \n", (size_t) msg->allocated_len);
return 0;
}
So it prints out:
msg->str = [this is my message]
msg->len = 19
msg->allocated_len = 512
The only strange is why the allocated_len is 512 instead of 256.
Thanks to everyone for the reply...
Resurrection, debugging led me to the next solution. Thank you Hasturkun for your help, I wanted to post my answer since yesterday but new members cannot answer their questions before 8 hours pass. The solution is this:
int main(void)
{
GString *msg = NULL;
gchar *p;
gchar buf[256];
msg = g_string_sized_new(256);
printf ("Enter a message (255 characters at most): ");
p = fgets(buf, sizeof(buf), stdin);
g_string_assign(msg, buf);
printf("msg->str = [%s] \n", (char *) msg->str);
printf("msg->len = %u \n", (size_t) msg->len);
printf("msg->allocated_len = %u \n", (size_t) msg->allocated_len);
}
And it prints out everything very well...
Thank you all for your comments!
Related
I am trying to use _snwprintf_s to concatenate two strings. I also want to append \r\n after each string.
So I allocate a wchar buffer initially including the \r\n and null for both strings. I try to print one after the other.
I see both strings are written. But when trying to free(wbuff), it throws me a "Heap corruption" error. I am not able to figure where I am crossing the bounds.
Where am I going wrong? Let me know. Thanks
int main()
{
WCHAR* name1 = L"HelloWorld";
WCHAR* name2 = L"GoodMorning";
WCHAR* wbuff = NULL;
int i = wcslen(name1) + wcslen(name2) + 6; //in words for size of buffer
int out = 0;
wbuff = (WCHAR*)malloc(i * sizeof(WCHAR));
ZeroMemory(wbuff, i * sizeof(WCHAR));
int prevLen = 0, currLen = 0;
currLen = wcslen(name1) + 2; //in bytes
out = _snwprintf_s(wbuff,i,currLen, L"%s\r\n", name1);
printf("Wrote %d characters\n", out);
prevLen = currLen;
currLen = wcslen(name2) + 2;
out = _snwprintf_s((wbuff+prevLen),i,currLen, L"%s\r\n", name2);
printf("Wrote %d characters\n", out);
printf("%S of sisze %u", wbuff, wcslen(wbuff));
free(wbuff);
printf("memory freed\n");
}
_snwprintf_s fills up the remaining characters in the buffer with an fefe marker. I can't find this in the documentation, but I can see it in the debugger. Hence, your second _snwprintf_s is indicating it's got i characters available, but your start position is prevLen chars into it. Fix i to have the offset adjustment as well.
Instead of this:
out = _snwprintf_s((wbuff+prevLen),i,currLen, L"%s\r\n", name2);
This:
out = _snwprintf_s((wbuff+prevLen),i-prevLen,currLen, L"%s\r\n", name2);
_snwprintf_s will fill up the entire buffer with markers
Instead of this:
printf("%S of sisze %u", wbuff, wcslen(wbuff));
This:
printf("%ls of sisze %u", wbuff, (unsigned int)(wcslen(wbuff)));
I want to split this string
kim-tae-yeon
and put them into different variables, like this:
data[1] = "kim" data[2] = "tae" data[3] = "yeon"
but I only split the string without store them to these variable.
How can I do this?
Here is my code:
char buff[] = "kim-tae-yeon";
int i = 0;
char *p = strtok (buff, "-");
char *data[3];
while (p)
{
data[i++] = p;
p = strtok (NULL, "-");
}
for (i = 0; i < 3; i++)
{
printf ("%s\n", &data[i]);
}
return 0;
}
Your program works well. The error comes by the fact that you are passing to printf &data[i] but datais an array of pointers (char *[]), which means each entry of the array is a pointer (char *). You want pass to printf a string, data[i].
This is the output you want:
for (i = 0; i < 3; i++)
{
printf("data[%i] = %s\n", i+1, data[i]);
}
As in the comment were said, there is no data[3].
The array starts at data[0], this is a default of C.
You can still have the output
data[1] = kim
data[2] = tae
data[3] = yaeon
by adding 1 to i,
but this output doesn't represent your actual data array.
This is wrong:
printf("%s\n", &data[i]);
The %sformat specifier requires a char* but you provided a char **(pointer to pointer to char). data[i] is already a char *, therefore you need:
printf("%s\n", data[i]);
If you had compiled with all warnings enabled (-Wall option with gcc) your compile would have told you this.
If you're ready to limit the length of the substrings, this can be solved much easier and less scary (strtok() is scary, come on!) using plain old sscanf():
const char buff[] = "kim-tae-yeon";
char data[3][32];
if (sscanf(buff, "%31[^-]-%31[^-]-%31[^-]", data[0], data[1], data[2]) == 3)
{
printf("parts are '%s', '%s' and '%s'\n", data[0], data[1], data[2]);
}
The format specifier, which is repeated three times with dashes in-between, is %31[^-], this means "collect at most 31 non-dash characters". The 31 makes sure there's room to terminate in our 32-character buffers.
It's a bit non-DRY with the buffer size repeated in the format string, the easiest fix for this is to generate the format string at run-time using snprintf(), but that obscures the issue so I didn't do that.
Something like this can work. It instead uses strcpy to copy over the string being pointed at, in this case buffer, to the space in data[i].
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define STRSIZE 50
#define NUMWORDS 3
int
main(void) {
char buff[] = "kim-tae-yeon";
char data[NUMWORDS][STRSIZE];
char *buffer;
int i;
buffer = strtok(buff, "-");
i = 0;
while (buffer != NULL) {
strcpy(data[i], buffer);
printf("data[%i] = %s\n", i+1, data[i]);
buffer = strtok(NULL, "-");
i++;
}
return 0;
}
Specifically, I am trying to build up the following statement and run it as the following command:
system("java -cp . mainpackage.SomeClass 1234567890 98765");
I have researched this online, but the examples did not compile, so I pieced together the following illustrative pseudo code. How do I change the code below to get it to concatenate the string and execute the command?
#include <stdio.h>
main() {
char jv[33];
strcpy(jv, "java -cp . mainpackage.SomeClass ");
char to[10];
strcpy(to, "1234567890 ");
char pin[5];
strcpy(pin, "98765");
system(jv + to + pin);
}
to and pin are arguments sent to a java program. Eventually, to and pin will be coming from inputs, but for now I just want to treat them as these values while I test other pieces of the code.
snprintf() is a flexible and a safe method. #fukanchik. The main challenge in C is to:
1) manage string memory space and
2) prevent overruns.
const char *jv = "java -cp . mainpackage.SomeClass ";
const char *to = "1234567890 ";
const char *pin = "98765";
#define BIGBUF 100
char command[BIGBUF];
snprintf(command, sizeof command, "%s%s%s", jv, to, pin);
system(command);
Or with C99 and assuming integers
const char *jv = "java -cp . mainpackage.SomeClass";
long to = 1234567890;
long pin = 98765;
int n = snprintf(NULL, 0, "%s %ld %ld", jv, to, pin);
char command[n+1];
snprintf(command, sizeof command, "%s %ld %ld", jv, to, pin);
system(command);
From an actual command line, like int main (int argc, char **argv)
char buf[1024] = {0};
int n;
for (n = 0; n < argc; n ++)
strcat (buf, argv[n]); // Change to strlcat if you have it available (BSD or Mac)
printf ("result = %s\n", buf);
Or using your example:
char jv[33];
strcpy(jv, "java -cp . mainpackage.SomeClass ");
char to[10];
strcpy(to, "1234567890 ");
char pin[5];
strcpy(pin, "98765");
system(jv + to + pin);
char result[1024] = {0}; // C does not zero format variables inside a function, so we do it ourselves with = {0}
sprintf (result, "%s %s %s", jv, to, pin); // Should use snprintf instead if available
printf ("result = %s\n", result);
OR
char result[1024] = {0};
strcat (result, jv);
strcat (result, " ");
strcat (result, to);
strcat (result, " ");
strcat (result, pin); // Should use strlcat instead if available
printf ("result = %s\n", result);
First, let me tell you the mistakes in above code.
char jv[33];
strcpy(jv, "java -cp . mainpackage.SomeClass ");
in C, strings are null-terminated, so you'll be needing an extra element per string to store the null. Expand the size of your array.
The, for concatenation like
system(jv + to + pin);
you can define an array large enough to hold the concatenated final value and use strcat() to concatenate the source and destination string. You can use a loop, to append more than one sub-string to make a complete command-string, as you want.
I'm trying to make a program where a user inputs a string then if they want to enter a letter they want to replace and what with. I want to use malloc to set the array but how would I do it with scanf?
Please can someone help.
Thanks!
This is what the program looks before going to the replace method:
char *s,x,y;
printf("Please enter String \n");
scanf("%s ", malloc(s));
printf("Please enter the character you want to replace\n");
scanf("%c ", &x);
printf("Please enter replacment \n");
scanf("%c ", &y);
prinf("%s",s);
You can't know the size of the user input beforehand, so you need to dynamically allocate more memory if the user input hasn't ended yet.
An example would be:
//don't forget to free() the result when done!
char *read_with_alloc(FILE *f) {
size_t bufsize = 8;
char *buf = (char *) malloc(bufsize);
size_t pos = 0;
while (1) {
int c = fgetc(f);
//read until EOF, 0 or newline is read
if (c < 0 or c == '\0' or c == '\n') {
buf[pos] = '\0';
return buf;
}
buf[pos++] = (char) c;
//enlarge buf to hold whole string
if (pos == bufsize) {
bufsize *= 2;
buf = (char *) realloc((void *) buf, bufsize);
}
}
}
A pragmatic alternative solution would be to limit the buf size (for example, to 256 characters), and to make sure that only that number of bytes is read:
char buf[256]; //alternative: char *buf = malloc(256), make sure you understand the precise difference between these two!
if (scanf("%255s", buf) != 1) {
//something went wrong! your error handling here.
}
scanf("%s ", malloc(s));
What does this mean? s uninitialized is pointer, it can have any value, say 0x54654, it is Undefined Behavior.
Your code should be,
int size_of_intput = 100; //decide size of string
s = malloc(size_of_intput);
scanf("%s ", s);
I am a newbie in c programming language and I have a university tutorial assignment that is related with working with chars(I wont be graded for this assignment) where you have to count words, I have to compile and submit my answers in an online web environment where my code will run against test cases that are not visible to me.here is my assignment:
Write the function 'wc' which returns a string containing formatted as follows: "NUMLINES NUMWORDS NUMCHARS NUMBYTES" .
Whitespace characters are blanks, tabs (\t) and new lines (\n). A character is anything that is not whitespace. The given string is null-char (\0) terminated.
here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* wc(char* data) {
char* result ;
int numLine ;
int numWords ;
int numChars ;
int i;
int numBytes =strlen(data);
char* empty=NULL;
while(strstr(data,empty)>0){
numWords=1;
for (i = 0; i < sizeof(data); i++) {
if(data[i]=='\n'){
numLine++;
}
if(data[i]==' ' ){
numWords++;
}
if(data[i]!=' '){
numChars++;
}
}
}
sprintf(result, "%d %d %d %d", numLine, numWords, numChars, numBytes);
return result;
}
this code will give me the correct output result but I am missing something here at least the test tells me that.
You've got a very serious error:
char* result;
...
sprintf(result, "%d %d %d %d", numLine, numWords, numChars, numBytes);
This is not allowed in C. You need to allocate sufficient memory for the string first. Declare result as a large enough static array, or use malloc if you've covered that in your course.
e.g.
char buf[100]; // temporary buffer
sprintf(buf, "%d %d %d %d", numLine, numWords, numChars, numBytes);
char *result = malloc(strlen(buf) + 1); // just enough for the string
strcpy(result, buf); // store the string
return result;
What if you have this input?
Two Words.
You have to count the transitions between whitespace/non-whitespace, not just count spaces.
Also, I'm pretty sure strstr(data,NULL) will not do anything useful.
You also appear to be missing the \t for tab in your white space checker, and you're not correctly checking when you're in or out of a word. You can use the boolean type bool for this defined in stdbool.h for this.
Source code of wc unix command:
http://www.gnu.org/software/cflow/manual/html_node/Source-of-wc-command.html
All test cases handled.
1) sizeof is wrong:
Instead of sizeof operator you need to use strlen() in for loop, like:
for (i = 0; i < strlen(data); i++)
^ not sizeof
sizeof(data) returns only size of data pointer address that is 4. Because you are to read all char in data[] you need strlen() that will return length of data[] (or number of chars in data[])
2) memory error:
Next Error I can notice there is no memory allocated for result. it declare like:
char* result ;
and No memory allocate! and you are writing using sprintf that cause undefined behavior of your code
3) while(strstr(data,empty)>0) is wrong
strstr() search position of a string in to other you empty string is NULL , CHECK:
char *strstr(const char *s1, const char *s2);
you strstr() always returns data, Why are you calling this? I believe you don't need this while() loop.
I improved you code upto some extend as below, There was only three error as I mentioned above now corrected(to understand read comments), You basic algo is correct:
#define SIZE 256 // added size macro
char* wc(char* data)
char* result = malloc(SIZE*sizeof(char)); //(2) allocated memory for result
int numLine ;
int numWords ;
int numChars ;
int i;
int numBytes =strlen(data);
numWords=1;
// (3) remove while loop
for (i = 0; i < strlen(data); i++) { //(1) change size
if(data[i]=='\n'){
numLine++;
}
if(data[i]==' ' ){
numWords++;
}
if(data[i]!=' '){
numChars++;
}
}
sprintf(result, "%d %d %d %d", numLine, numWords, numChars, numBytes);
return result;
}
int main(){
printf("\nresult: %s\n", wc("q toei lxlckmc \t \n ldklkjjls \n i \t nn "));
return 1;
}
Output:
result: 2 14 28 41