[ / / / / / / / / / / / / / ] [ dir / arepa / asatru / fascist / hwndu / komica / loomis / marx / vichan ][Options][ watchlist ]

/prog/ - Programming

Programming board
You can now write text to your AI-generated image at https://aiproto.com It is currently free to use for Proto members.
Name
Email
Subject
Comment *
Password (Randomized for file and post deletion; you may also set your own.)
* = required field[▶ Show post options & limits]
Confused? See the FAQ.
Expand all images

File (hide): 7d1c8b287f129b3⋯.png (9.58 KB, 670x164, 335:82, ClipboardImage.png) (h) (u)

[–]

595ba4 (3) No.4804>>5172 [Watch Thread][Show All Posts]

I was doing homework, and here is my code:

#include <stdio.h>
#include <string.h>
main()
{
char word1[25], word2[13], spc1[1] = " ";

p1:
printf("Type your first word.");
scanf("%s", &word1);
if (strlen(word1) > 12)
{
printf("Error. Word is too big.");
goto p1;
}

p2:
printf("Type your second word");
scanf("%s", &word2);
if (strlen(word2) > 12)
{
printf("Error, word is too big.");
goto p2;
}

strcat(word1, spc1);
printf("New word is: %s", word1);
}

So basically, the question asked for me to create a program where the user would type 2 words, but none could be greater than 12 characters. That being ok, I would need to concatenate those words and print as a 1 word only. My first problem was that the print had no space between the words. Example, if the entry was "Infinite Chan" it would print "InfiniteChan".

I then created a new string called spc1 that would be a space " ", I would then concatenate word1 to space and then the new word ("Infinite ") would be concatenated to word2, printing "Infinite Chan". But hell, the thing is working with just strcat(word1, spc1); . When I print, the output is correct, "Infinite Chan".

Why is that?

8d8013 (3) No.4805>>4806

* You need a return type for main, and to return from main.

* You don't need the address operator to get the address of the array, it only incidentally works here because the address of an array on the stack is treated the same as the address of the first element, and doing that could cause you serious issues if you ever try to dereference it, as you'll get the first chunk of the array but treated as a (char *)

* Using scanf like that is not safe. You can very easily overrun your buffer. If somebody input a 50-character word, you'd get a buffer overrun. You shouldn't use strlen, because scanf will return the length of the string. You should be using %ms if you can to allocate the buffer dynamically and avoid an overrun, and build a fresh buffer from the results, rather than setting size limits. This isn't a big deal, because it's homework, so safety isn't a major concern.

* Use a loop, not gotos. They shouldn't be teaching gotos at any point ever for a C class. There is almost no valid reason to use them, especially for ordinary flow control and especially in an educational context.

I'll explain in detail what is causing your issue. It's actually fairly interesting, and there are a few things at play here.

1: Your spc[1] is too small for " ", so it doesn't get a trailing NULL byte (NUL is the common designation for the NULL byte, so I'll use it from here on out).

2: Local variables are assigned on the program stack.

3: Stack memory is allocated backwards (from high memory to low memory), which causes your local memory layout to be spc, word2, word1.

4: You put "Infinite" fine into word1, with a trailing NUL.

5: You put "Chan" fine into word2, with a trailing NUL.

6: You strcat spc1 onto word1, but spc1 didn't have enough room for the NUL, so it didn't get it. Immediately after spc1 is word2, so the strcat runs right through to the end of word2 (as it does not stop until it hits a NUL), and puts the whole thing into word1.

If you wanted to still do it your way, you should define spc1 as a (const char *), not a char[1]. You don't need a mutable buffer if you aren't going to change the buffer. You could also just do a strcat(word1, " "), as strcat accepts a (const char *), which string literals are.

It's a very good thing that you asked this question. You wouldn't want to rely on this errant behavior. It's very bad behavior and only incidentally ends up doing what you want it to do in this specific situation. If you had defined spc1 before word1, for instance, you can easily get a segmentation fault and crash your program, and that's a good case scenario. Worst-case scenario is that you've introduced a serious security vulnerability or can leak sensitive information from the program (this is similar to what caused the Heartbleed vulnerability).


595ba4 (3) No.4806>>4807

>>4805

Thank you for the answer. I 'm still very new to programming, so some things doesn't make much sense to me, but I think I was able to get the idea.

About the use of goto, strlen and so on, those are the commands I know for now, so I have to deal with them. I think it's weird that they would teach goto if it is so useless, but They (the college) haven't taught us (the class) loop yet, so life is hard.

I was able to make the program work with const char*, but I never heard about char* before, so I will have to figure out another way to make this exercise.

Thank you for everything.


8d8013 (3) No.4807>>4809

>>4806

A lot of classes teach gotos before loops, but it's really bad. Do things the way the class tells you to, but keep in mind that you will likely never use goto again as a programmer when you stop having to use it for school. You can find lots of papers and discussions on why goto is bad ( http://www.u.arizona.edu/~rubinson/copyright_violations/Go_To_Considered_Harmful.html ). You don't have to worry about any of those reasons where you are now, just keep them in mind in the future when you are doing your own programming or working. They'll teach you how they're going to teach you, but they should start with loops before they ever work with IO like scanf. Loops should be the very first thing you learn after conditionals ("if" is a conditional).

char * is a pointer. It means "this is a memory address that points to a character". An array of characters (or a string) is a contiguous block of memory that holds characters. When you use an array (or string) as a pointer, it gives you an address to the beginning of the block of memory. That's why char * works, because it doesn't try to treat it as a literal array of a specific size, it just knows that it's pointing to a string of any size, so you don't get the size mismatch you had.

Like I said, you can also change your spc1[1] to a spc1[2] to make it work without a pointer (because you need size for all the characters as well as a trailing NUL), or you can just use the string literal in your strcat and not store spc1 as a variable at all.


8d8013 (3) No.4808>>4809

And by the way, you explaining exactly the behavior you are having as well as providing a code example puts you head and shoulders above tons of experienced programmers who don't understand this shit.

One of the most important skills to have as a programmer (probably the very most important) is the ability to properly ask for help.

If you are asking for help but you don't both explain exactly what issue you are having and post example code that demonstrates your issue so that people can run the code and see it for themselves, 90% of people who can help you will ignore it, because it's too much work to decipher exactly what you've got going wrong. You want to make it as easy as possible for people to help you (I usually point people to http://sscce.org/ ).

I've got coworkers, even, who ask me for help and I have to wrestle exactly what their issue is out of them. I'll spend like an hour figuring out what their problem is because they haven't narrowed it down and then 5 minutes actually helping them, because they don't know how to properly ask for help.


595ba4 (3) No.4809

>>4808

>>4807

Thank you, man, I was able to understand everything better now. Now that I can see better why it wasn't working I got what you meant by saying that the problem was fairly interesting.

Thank you for the tips and the compliments.


228f63 (1) No.4825

File (hide): d0eac2a9688ac4d⋯.png (50.2 KB, 699x770, 699:770, RemoveRust.png) (h) (u)

This is why I love C.

REMOVE RUST


809eed (5) No.4912>>4913 >>4914

File (hide): 39795636dd22ff6⋯.jpg (303.24 KB, 2032x900, 508:225, brickado supremo do sky3ds….jpg) (h) (u)

Hey, OP here again. I have a new question, this time is in pyhton. Here is the exercise:

>Using the following list, create a program that prints out all numbers that are less than 5.

>list_a = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]

And here is how I solve it:


list_a = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]

x=0

while list_a[x]<5:
print(list_a[x])
x+=1

Is there a problem in using a while instead of an if? Is this something common to do or it something like "you shouldn't do it because is wrong, people will not understand, etc"?


809eed (5) No.4913

>>4912

Shit, just found a bug. If there's a 3, for example, after the 5, the program will stop and not print it.

Anyway, besides that, is there any problem in doing it?


6a10b3 (2) No.4914>>4915 >>4922

>>4912

>while list_a[x]<5:

The problem is that you are doing two array lookups per loop.

In Python, when all you do with an index is scan through an array, you don't need the index at all:


for item in list_a:
# do something with item

However, if printing is all you do you should use:


print (" ".join (map (str, filter (lambda x: x < 5, list_a))))

If you know for a fact that your input is sorted, such as the fibonacci sequence, you can stop at the first limit breaker:


print (" ".join (map (str, itertools.takewhile (lambda x: x < 5, list_a))))

If you need the numbers for more than something trivial like printing, you can get them with:


under5 = [n for n in list_a if n < 5]

or in the sorted case:


under5 = list (itertools.takewhile (lambda x: x < 5, list_a))

Still in the sorted case, and with a list, you can do even better with a binary search:


limit = bisect.bisect_left (list_a, 5)
under5 = list_a [:limit]
print (" ".join (map (str, under5)))
# print (under5)

https://docs.python.org/3/library/itertools.html#itertools.takewhile

https://docs.python.org/3/library/bisect.html#bisect.bisect_left


809eed (5) No.4915

File (hide): 0b9f50d0fa0de52⋯.jpg (105.79 KB, 1180x842, 590:421, thums up.jpg) (h) (u)

>>4914

Thank you for the nice explanation. I'm still learning, so I didn't know python could simplify things that much.

I will look into the resources you gave, since some functions in there are unknown to me, after reading the doc I bet things will make more sense.


809eed (5) No.4920>>4922 >>4926

File (hide): 91963916dff75b5⋯.png (5.3 KB, 694x250, 347:125, ClipboardImage.png) (h) (u)

Why pic related does not work but the code below does?


# write a program that returns a list that contains only the elements that are common between the lists
# (without duplicates). Make sure your program works on two lists of different sizes.

a = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]

nlista = []

for x in a:
if x in b and x not in nlista:
nlista.append(x)

print(nlista)


6a10b3 (2) No.4922>>4923

>>4920

You can use several code blocks in a single post, like you see in >>4914. Post the problem code as text in code tags; don't post code as an image.

Python has built-in support for sets and set operations like intersection. Alternatively, if your inputs are already sorted, use the merge step of mergesort to get a linear algorithm instead of your current quadratic one.

https://docs.python.org/3/library/stdtypes.html#set-types-set-frozenset


809eed (5) No.4923>>4926

>>4922

Sorry about that, I will keep it in mind.

Thanks for the help with the intersection function.


a = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]

lista = set(a).intersection(b)

print(lista)


4d06c7 (1) No.4926

>>4920

for x in a and x in b:

This construct does not exist in Python. "and" is nothing more than a boolean operator. If you wanted to iterate over both, you need nested loops (which the "in" and "not in" operators would essentially achieve for you). The other poster is right about sets, but remember that python sets have special semantics that can make this kind of use more intuitive:


a = {1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89}
b = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}
nlista = a & b
print(nlista)

Or, if "a" and "b" have to be given to you as lists, you can do what >>4923 did, but using the special operators and casting:


a = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]

lista = set(a) & set(b)

print(lista)

It does the exact same thing, but is possibly more clear. Which one you prefer is really up to style and the situation at hand.

What your image looked like it was trying to do, which is a very naive non-set solution, would look like this done in the most simple possible way:


a = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]

nlista = []

for x in a:
if x in b and x not in nlista:
nlista.append(x)

print(nlista)

Note that a set solution will not maintain order. If you need to maintain order of the elements, you should turn the other list into a set and use that, (like the last solution above, but with b turned into a set for performance gain).


e320ab (1) No.5172

>>4804 (OP)

I honestly skipped reading most of the thread but why not do a while loop that references the number of characters in the 2 strings


while (a < 1 && b < 1)
print("enter at least 1 character for each of the 2 words")
Input a_string
a = number of characters in a_string
Input b_string
b = number of characters in b_string
while (a > 12 && b > 12)
print("too many characters")
Input a_string
a = number of characters in a_string
Input b_string
b = number of characters in b_string
print concatenated a_string and b_string

bot of course way more elegant than that




[Return][Go to top][Catalog][Screencap][Nerve Center][Cancer][Update] ( Scroll to new posts) ( Auto) 5
15 replies | 4 images | 7 UIDs | Page ?
[Post a Reply]
[ / / / / / / / / / / / / / ] [ dir / arepa / asatru / fascist / hwndu / komica / loomis / marx / vichan ][ watchlist ]