Welcome, Guest. Please login or register.

Author Topic: Executing c command in c  (Read 9192 times)

Description:

0 Members and 1 Guest are viewing this topic.

Offline foleyjoTopic starter

  • Hero Member
  • *****
  • Join Date: Nov 2005
  • Posts: 608
    • Show only replies by foleyjo
Re: Executing c command in c
« Reply #44 from previous page: May 30, 2017, 01:55:27 PM »
Had a typo there. List_items->max_number is my char *. Should have been a , after it.
I think it'll be easier to make it an int inside the structure. I had problems. Not sure why I did it as a char chat in the first place. Think I was getting a crash and changing it fixed things. Should have known it would come back to haunt me.
I'll check out snprintf too
 

Offline olsen

Re: Executing c command in c
« Reply #45 on: May 30, 2017, 02:38:04 PM »
Quote from: foleyjo;826408
Had a typo there. List_items->max_number is my char *. Should have been a , after it.
I think it'll be easier to make it an int inside the structure. I had problems. Not sure why I did it as a char chat in the first place. Think I was getting a crash and changing it fixed things. Should have known it would come back to haunt me.
I'll check out snprintf too


You might want to look at your data structure definitions, pondering whether each member's name suggests both its purpose and its content.

If a structure member would be named "max_number", and its purpose is to show that number in text form, "max_number_label" might be a better name.

As short as member names should be, every name tells a story and suggests how you might use it. If the first glance gives an impression that doesn't fit well or may even be misleading, then you are bound to make mistakes. This might be less of a problem in short programs, but as you are building larger and larger programs, you should not need to rely upon memorizing structure names, their respective member names and their purposes.
 

Offline foleyjoTopic starter

  • Hero Member
  • *****
  • Join Date: Nov 2005
  • Posts: 608
    • Show only replies by foleyjo
Re: Executing c command in c
« Reply #46 on: May 30, 2017, 03:06:34 PM »
Thanks for the tip.
I changed it to an int and now it works as expected. I created it as a char because I didn't understand pointers.
I've just been through my code and comments and realised one of my functions uses char ** .
When I tried to make a similar function to work with integers and not strings I had used int ** instead of int*.
I found a good tutorial on pointers and addresses  so was able to spot the mistake this time and understood why it caused a problem.

Just been reading about snprintf and I had come across it before but there is lots of conflicting information.
sprintf,snprintf,strcpy and strncpy all seem to have people saying you should use them or you shouldn't use them.
I tend to malloc my destination string to the size of the source string and then add a null terminator
 

Offline olsen

Re: Executing c command in c
« Reply #47 on: May 30, 2017, 03:25:01 PM »
Quote from: foleyjo;826417

Just been reading about snprintf and I had come across it before but there is lots of conflicting information.
sprintf,snprintf,strcpy and strncpy all seem to have people saying you should use them or you shouldn't use them.


Well, you need to know why each one would be a poor choice.

strcpy() and strncpy() are part of the basic 'C' language runtime library. They go way back when the programmers who would use them could be relied upon to be intimately aware of the limitations of these functions. Nowadays you should try to avoid them because neither function knows when to stop if it has to copy strings to a destination of limited size.

If you use strcpy() to copy a 16 character string to a string buffer which can only hold 4 characters, strcpy() doesn't know that it should stop after the 3rd character.

The strncpy() function is a special version of strcpy() in that it will copy only a fixed number of characters, but it might not add a NUL termination. There are few reasons for using strncpy() in the first place. You will probably find that the conditions under which strncpy() makes sense apply only a handful of times during your 'C' programming career.

sprintf() has the same problem as strcpy(): it will put text into the output string buffer without regard for that buffer's size. Again, if sprintf() wants to put 16 characters into the output string buffer, and that buffer is just 4 characters in size, sprintf() will not stop after the 3rd character.

What you should be using instead of strcpy() is a function call strlcpy(). strlcpy() can be told how many characters (including the NUL) will fit into the output string buffer. It will stop copying if the output buffer turned out to be too short. Better still, strlcpy() will always make sure that the output string buffer is properly terminated by a NUL. There's one exception: if you tell strlcpy() that the output buffer is 0 characters in size it will not copy anything.

In case you were wondering, there is a strlcat() function which should be used rather than strcat(), too.

Instead of using sprintf(), use snprintf(). It's the same deal as with strcpy() vs. strlcpy(): snprintf() can be told how many characters will go into the output string buffer. If the output buffer turns out to be too short to hold everything snprintf() might want to store there, it will stop before overrunning the output string buffer.

Quote

I tend to malloc my destination string to the size of the source string and then add a null terminator


If that's all that needs to be done here, you might want to try strdup() instead. This will allocate memory for the NUL-terminated string, copy the original string over and return the copied string. It's a standard 'C' runtime library function.
 

Offline foleyjoTopic starter

  • Hero Member
  • *****
  • Join Date: Nov 2005
  • Posts: 608
    • Show only replies by foleyjo
Re: Executing c command in c
« Reply #48 on: May 30, 2017, 03:50:24 PM »
tried strdup() previously and just tried strlcpy().

For both I get no prototype function.
Guessing that relates to the compiler I'm using (Storm C 3.0) .

So really I should be using snprintf in the places where I used strcpy.
I actually used strcpy because the tutorial I read said I shouldn't use sprintf. I only started using sprintf when I was looking for a way to write an integer into a string and that's when I started reading the reverse argument that strcpy shouldn't be used. Both arguments talked of the snprintf and strncpy but again both claimed 1 should be used and the other was bad.
 

guest11527

  • Guest
Re: Executing c command in c
« Reply #49 on: May 30, 2017, 05:32:18 PM »
Quote from: foleyjo;826421
tried strdup() previously and just tried strlcpy().

For both I get no prototype function.
Guessing that relates to the compiler I'm using (Storm C 3.0) .
Unfortunately, strlcpy() is not an ANSI-C function but a compiler extension some compilers provide, and unfortunately, strncpy() has its quirks as mentioned by Olaf (namely, not NUL-terminating strings). strdup() is ANSI-C.

Anyhow, regardless of this: It might make a good exercise anyhow to attempt an implementation of these two functions if your compiler does not provide them. It's not really hard to do that, and unless your code is really time-critical (hint: it usually is not), your own versions may do just fine.


Quote from: foleyjo;826421
So really I should be using snprintf in the places where I used strcpy.
Note that this is not a 1:1 substitute. snprintf() comes from the printf() family and does "quite a lot of work", whereas strcpy() is a simple string copy without much intelligence.

snprintf() is a possible substitute for sprintf(), but to use it properly, the return code of the function should be checked as to detect cases, where the buffer would overrun. While this no longer corrupts memory (unlike sprintf()), it still means that the output it generated is probably not what you want - after all, it was truncated. A possible strategy would be to allocate a buffer given the return code of snprintf, and then use that....

Anyhow. As you see, writing good, robust C code is not exactly trivial, due to many legacies of the language (C++ is a bit better in this respect, but also more complex...).



Quote from: foleyjo;826421
I actually used strcpy because the tutorial I read said I shouldn't use sprintf. I only started using sprintf when I was looking for a way to write an integer into a string and that's when I started reading the reverse argument that strcpy shouldn't be used.
sprintf() can be used to convert an int to a char[] - or rather write it into a given buffer - while strcpy() certainly can't, so the purpose of the two functions is quite different. The way how C handles "strings" is quite archaic (actually, it only really has character arrays and string literals, nothing like a "string" as you might know from other higher languages).


Quote from: foleyjo;826421
Both arguments talked of the snprintf and strncpy but again both claimed 1 should be used and the other was bad.
It really depends on what you want...

sprintf() can trash memory if you are not careful enough, snprintf() cannot, but it has similar drawbacks: Its output (or rather, it's side-effect - the letters in the buffer, let's be precise) can be truncated, making it useless in such cases.

So for the matter of this little tutorial: On the Amiga, a
Code: [Select]
char buffer[12];
sprintf(buffer,"%d",number);
is perfectly safe, because ints are here at most 32 bits wide and hence *cannot possibly* be longer than 11 digits (plus NUL-termination gives 12).

So *in this case* we are perfectly safe. However, in other cases, it is not quite as trivial as how to compute as how long the result of sprintf() could possibly be, and in such cases,
Code: [Select]
char buffer[MAXBUFSIZE];
if (snprintf(buffer,something_complex,complex_arguments) >= MAXBUFSIZE) {
fprintf(stderr,"buffer overrun!\n");
exit(25); /* or some better mechanism how to handle this case - as in : enlarge the buffer */
}
is the better alternative. Unfortunately, it's not simple.
 

Offline foleyjoTopic starter

  • Hero Member
  • *****
  • Join Date: Nov 2005
  • Posts: 608
    • Show only replies by foleyjo
Re: Executing c command in c
« Reply #50 on: May 31, 2017, 11:07:34 PM »
Ok I solved my issue for this post.I had a do while instead of a while do which was causing silly things to happen. My 2nd question I still don't know so leaving it below
Which leads me to a curiosity I have.
If calloc is used to assign memory for an array and a string is an array of characters, why is calloc not used for strings (at least not in the examples I can find)
« Last Edit: May 31, 2017, 11:34:48 PM by foleyjo »
 

guest11527

  • Guest
Re: Executing c command in c
« Reply #51 on: June 01, 2017, 07:47:53 AM »
Quote from: foleyjo;826545
If calloc is used to assign memory for an array and a string is an array of characters, why is calloc not used for strings (at least not in the examples I can find)
You can also use calloc to allocate character arrays (aka "strings") of course, no problem. C is a very low-level language. It does not really care where the memory came from, provided it is sufficient memory for the task at hand. You can use malloc, you can use calloc....

If you look at it, calloc is really only a very thin wrapper around malloc, performing one multiplication, and an additional zero'ing of the array afterwards, so most people simply don't bother.
 

Offline olsen

Re: Executing c command in c
« Reply #52 on: June 01, 2017, 09:43:40 AM »
Quote from: foleyjo;826545
Ok I solved my issue for this post.I had a do while instead of a while do which was causing silly things to happen. My 2nd question I still don't know so leaving it below
Which leads me to a curiosity I have.
If calloc is used to assign memory for an array and a string is an array of characters, why is calloc not used for strings (at least not in the examples I can find)


The 'C' runtime library contains several functions which deal with memory management. Each serves a specific purpose, although it is hard to say today why they all wound up in the library. There is malloc(), calloc(), realloc() and strdup(). Each of these functions may return a pointer to allocated memory which can be released with free(), or passed to realloc().

calloc() is one of the odd functions in this list. It will allocate memory for you, and if successful, will fill the allocated memory with zeroes. How you tell calloc() how memory is needed is rather peculiar: instead of asking for a certain number of bytes (like you would do with the malloc() and realloc() functions), calloc() wants to know how to break down the total allocation size into portions, and how many portions are required.

To answer your question: calloc() can be used to allocate memory for strings, but since calloc() does so much more than is needed if all you intend is to copy a NUL-terminated string into the buffer, malloc() does the same job just fine. malloc() is the simplest possible way to get this done.

Keep in mind that calloc() will fill the allocated memory with zeroes, and if you are going to copy the string into that memory, the zero-fill operation is not necessarily required. Also, calloc() wants you to break down the size into two parameters, this being a portion size and the number of portions required. malloc(), on the other hand, just needs to know the total size.
 

Offline olsen

Re: Executing c command in c
« Reply #53 on: June 01, 2017, 09:53:10 AM »
Quote from: foleyjo;826421
tried strdup() previously and just tried strlcpy().

For both I get no prototype function.
Guessing that relates to the compiler I'm using (Storm C 3.0) .


There's the rub. An older compiler will not support more modern library functions unless somebody takes the time to add them to it. You may be stuck with the state of the art at the time StormC 3.0 shipped.

Quote
So really I should be using snprintf in the places where I used strcpy.


Well, that depends upon what you need to accomplish. In my experience, the simplest possible tool that gets the job done tends to be the most appropriate.

snprintf() as well as sprintf() are mainly used for translating data (numbers, single characters, NUL-terminated strings) into text form.

If all you need is to copy one NUL-terminated string to a memory buffer, strcpy() may be a simpler solution. The drawback of strcpy() is that it does not respect output buffer boundaries, whereas snprintf(), if you have it, will do. In that case, snprintf() may be the safer alternative to strcpy() although it's purpose is not in copying strings, but in translating data into text form.

As a 'C' programmer you will have to make choices such as this (strcpy() vs. snprintf()) all the time. When the obvious solution would be the one you chose not to use, it's good practice to add a comment explaining briefly why the choice was made.

Quote

I actually used strcpy because the tutorial I read said I shouldn't use sprintf. I only started using sprintf when I was looking for a way to write an integer into a string and that's when I started reading the reverse argument that strcpy shouldn't be used. Both arguments talked of the snprintf and strncpy but again both claimed 1 should be used and the other was bad.

If the tutorial does not explain why one choice is better suited than the other, what can you do but ask us? :)
 

Offline foleyjoTopic starter

  • Hero Member
  • *****
  • Join Date: Nov 2005
  • Posts: 608
    • Show only replies by foleyjo
Re: Executing c command in c
« Reply #54 on: June 01, 2017, 02:41:47 PM »
Quote from: olsen;826554

If the tutorial does not explain why one choice is better suited than the other, what can you do but ask us? :)


I don't know where I'd be if it wasn't for asking you guys.
Actually yes I do. I'd have given up after "Hello world" .
I have a few bugs that are causing crashes relating to memory now. I may be able to solve them once I have stepped through the code.
Will probably be asking for help later though knowing me
 

Offline foleyjoTopic starter

  • Hero Member
  • *****
  • Join Date: Nov 2005
  • Posts: 608
    • Show only replies by foleyjo
Re: Executing c command in c
« Reply #55 on: June 02, 2017, 12:13:54 PM »
I got rid of the memory crashes.
Just a problem with my mui list now.
I have 2 columns ID and Name but only 1 displayed.
When an entry is clicked it should return the ID and then I use the ID to do tasks relating to the entry.
However the mui examples I found only return the item number in the list.
This is fine until I sort my list. Then the returned number and ID no longer match.

Now I think I need to use a compare hook. but I don't understand how the hooks work.
Or is there another way to return the correct ID.

This is the code I'm currently using to get the number of the item in the list
Code: [Select]

int num;
get (list_mylist,MUIA_List_Active,&num);
 

Offline Thorham

  • Hero Member
  • *****
  • Join Date: Oct 2009
  • Posts: 1149
    • Show only replies by Thorham
Re: Executing c command in c
« Reply #56 on: June 02, 2017, 01:16:11 PM »
Quote from: Thomas Richter;826432
Unfortunately, strlcpy() is not an ANSI-C function but a compiler extension some compilers provide
Why not implement simple things like that yourself? I usually don't bother with using the C runtime for strings at all. It bloats the executable for a few functions that are all a few lines of C. Furthermore, your own functions can be tailored to your exact needs.

Quote from: Thomas Richter;826549
C is a very low-level language.
I would call it a mid level language. Too high level compared to assembly language, and too low level compared to things like C#. Pointers != very low level ;)
« Last Edit: June 02, 2017, 01:23:03 PM by Thorham »
 

Offline Thorham

  • Hero Member
  • *****
  • Join Date: Oct 2009
  • Posts: 1149
    • Show only replies by Thorham
Re: Executing c command in c
« Reply #57 on: June 02, 2017, 01:22:22 PM »
Quote from: Thomas Richter;826432
Unfortunately, strlcpy() is not an ANSI-C function but a compiler extension some compilers provide

Why not implement simple things like that yourself? I usually don't bother with using the C runtime for strings at all. It bloats the executable for a few functions that are all a few lines of C. Furthermore, your own functions can be tailored to your exact needs.
 

Offline olsen

Re: Executing c command in c
« Reply #58 on: June 02, 2017, 02:18:37 PM »
Quote from: Thorham;826576
Why not implement simple things like that yourself? I usually don't bother with using the C runtime for strings at all. It bloats the executable for a few functions that are all a few lines of C. Furthermore, your own functions can be tailored to your exact needs.

Writing your own string processing functions does make sense. The challenges you will be facing are, however, not going to be smaller than the original designers of the 'C' runtime library had to deal with ;)

You still need to define what your own functions should do (not that hard), and you still need to test your code and document it.

If you are only just starting out writing 'C' code, you might consider the testing & documentation portion to be not that important (I certainly thought that I had more important things to do, back in 1988). 'C' being what it is, testing and documenting your code are essential for writing robust, working code, rather than creating code which keeps surprising you by the many ways in which it causes crashes, or sucks up time for debugging. That's true for most programming effort, but 'C' makes it much easier to shoot yourself in the foot, and much easier to do much higher damage as a result.

The standard 'C' runtime library has its limitations and knock-on effects (not all of them good), but you can at least expect it to be well-documented and well-tested.

The trade-off is in either working within the constraints of the 'C' runtime library and modestly filling in the gaps you perceive with code of your own design, or completely relying upon code of your own design.

The greater freedom afforded by using your own design can be an illusion. Returning to the code you wrote a little time later you might just find that it is underdocumented and/or less robust than you thought it was when you wrote it.

Lack of documentation is certainly a challenge if you have to explain to others how it works, and why it works that way. Relying upon the 'C' runtime library instead of going your own way at least has the advantage that the documentation already exists and need not be fully explained by yourself to others.
 

guest11527

  • Guest
Re: Executing c command in c
« Reply #59 on: June 02, 2017, 05:02:30 PM »
Quote from: Thorham;826576
Why not implement simple things like that yourself?
For the OP and the problem at hand, this would make at least a good exercise with a learning experience. It's simple enough, and you'll understand that there is no "magic" going on in the stdlib.

Quote from: Thorham;826576
I usually don't bother with using the C runtime for strings at all. It bloats the executable for a few functions that are all a few lines of C. Furthermore, your own functions can be tailored to your exact needs.
In general, I would advice against this. Not only for the reasons Olaf gave (documentation, portability, readability), but also that some compilers offer compiler built-ins for the most used and most useful functions. SAS/C generates inline assembly code for strlen, strcpy, memset and memcpy. You'll hardly beat that by providing your own implementations. Many other string functions come with assembly language implementations (strcat, memchr, strchr, strrchr and others), so it's typically worth it.

C is of course not very good at string processing anyhow (given that it has no native datatype for strings, this is not a miracle) and other languages can do better by optimizing needless string copies or memory handling away. If you know the data flow in your application, you can certainly avoid some "costly" operations like strcat. E.g. if you know the string length anyhow, a strcpy to the right place will do.

Quote from: Thorham;826576
I would call it a mid level language. Too high level compared to assembly language, and too low level compared to things like C#. Pointers != very low level ;)
Given that we have now interpreted languages like javascript or languages like scala that run on the JVM, C is "pretty low" to me. It's probably the next possible "higher" language if you don't bother touching assembler. (Leaving some exotic intermediate languages like C-- apart).