-2

Greetings,

I had been studying C++ for a while now. I'm getting in to pointers now. But I'm creating a program on C++ that will ask for a string("%s") input. And I want to display its character on a different line. But when I run the program I get the wrong letters. Here's my code;

#include<stdio.h>
#include<stdlib.h>
main() {
char* name;
name = (char *)malloc(sizeof(char));
printf("Enter string: "); scanf("%s", name);
while(*name != '\0') {
printf("%c", name); *name++
}
}

Your reply is highly appreciated.

Ben Collins
  • 20,538
  • 18
  • 127
  • 187
Cyril Horad
  • 1,555
  • 3
  • 23
  • 35
  • 6
    This is C, not C++. (And, yes, I know a C++ compiler will [almost] accept it. I'm talking about idioms and convention. _And the fact that `main()` requires a return type._) – Lightness Races in Orbit Apr 06 '11 at 14:57
  • No it's not C, since `malloc` is casted. It's neither :) – orlp Apr 06 '11 at 14:58
  • @nightcracker: You can cast the result of `malloc` just fine in C. (You just usually don't _need_ to.) – Lightness Races in Orbit Apr 06 '11 at 14:59
  • 1
    @shuttle87: Adding the `c` tag is not the solution. Let's pick _one_ language and stick with it. – Lightness Races in Orbit Apr 06 '11 at 14:59
  • 1
    You should also learn about indenting code. It really makes you life easier. Learn that and apply it starting today. – pmg Apr 06 '11 at 15:00
  • @Tomalak Geret'kal: You can include the C headers just fine in C++ (You just usually shouldn't). – orlp Apr 06 '11 at 15:00
  • @nightcracker: Touché. However, what you can't do in C++ is leave off `main`'s return type, which must be `int`. – Lightness Races in Orbit Apr 06 '11 at 15:01
  • 1
    @Tomalak Geret'kal: Touché. However no semicolon after `*name++` doesn't seem to be legal C either. Neither is defining `main` with `int` (absent type means `int` in C) and not returning anything from `main` legal C. – orlp Apr 06 '11 at 15:02
  • apology about the my confusion about c or c++. :D – Cyril Horad Apr 06 '11 at 15:03
  • 1
    More importantly, what you can't do is **learn C++** while writing C code. It's not a matter of whether or not it will work. The asker is clearly trying to learn the language (at least, that's why I study things). @Cyril: Do you have a good book about C++? That's really the best way to learn the language. There's [a good list here](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). – Cody Gray - on strike Apr 06 '11 at 15:03
  • @nightcracker: Heh, good spot ;) I guess we can both eschew it then. – Lightness Races in Orbit Apr 06 '11 at 15:04

4 Answers4

2

malloc(sizeof(char)) allocates space for a single character. This is probably not what you want. As the comments below point out, the dereferencing in *name++ is pointless. It does no harm, but perhaps indicates that you're thinking incorrectly about something. name++ has the same effect.

gspr
  • 11,144
  • 3
  • 41
  • 74
  • It's been a while since I used C in anger, but isn't `*name++` a perfectly common idiom for doing what is intended there? – Pete Apr 06 '11 at 15:01
  • And `printf("%c", *name);` rather than `printf("%c", name);` – a1ex07 Apr 06 '11 at 15:02
  • `*name++` is `*(name++)`. The dereference is harmless, but ultimately completely pointless here. In other scenarios it may be useful if you want to output and increment at the same time. – Lightness Races in Orbit Apr 06 '11 at 15:02
  • `*name++` is perfectly fine. The pointer will be dereferenced first, and then the `++` operator will be applied. @Tomalak Geret'kal, he probably meant to do `printf("%c", *name++);` – Ben Collins Apr 06 '11 at 15:03
  • @BenCollins: Wrong. `*name++` is `*(name++)`. – Lightness Races in Orbit Apr 06 '11 at 15:05
  • @Tomalak: Yeah, sorry about that. You're of course completely correct. – gspr Apr 06 '11 at 15:05
  • It's all coming back to me now, `printf ("%c", *name++)` – Pete Apr 06 '11 at 15:05
  • @Tomalak: no, I'm not wrong. If I were, this (http://pastie.org/1763712) wouldn't print the 'B' in my name, but it does. The reason you're wrong is the postfix `++` and unary `*` have the same precedence, but are applied in left-to-right order. – Ben Collins Apr 06 '11 at 15:21
  • @BenCollins: What nonsense. Your testcase works because the pointer is dereferenced and then the pointer incremented afterwards, since you used `ptr++` not `++ptr`. `*name++` **is** `*(name++)`; "the pointer will be dereferenced first" is simply _not true_. – Lightness Races in Orbit Apr 06 '11 at 15:59
  • @Tomalak: Ah - yes, you're right about the precedence of the operators. I misread the standard. – Ben Collins Apr 06 '11 at 16:07
  • 1
    @BenCollins: The "geordi prime" bot, running [`geordi`](http://www.xs4all.nl/~weegen/eelis/geordi/) and sitting on Freenode, is a great little tool. I just write `/msg geordi --precedence *name++` and the parser tells me `*(name++)` back. Highly recommended. – Lightness Races in Orbit Apr 06 '11 at 16:09
2

First, if you are going to study C++, you should learn to write C++ programs, not C programs. Here is your program in idiomatic C++:

#include <iostream>
#include <string>
int main(int, char **) {
    std::string name;
    std::cout << "Enter string: " << std::flush;
    std::cin >> name;
    std::cout << name << "\n";
}

One advantage of using C++ and its standard libraries over C and its standard libraries is precisely this: you almost never need to use pointers.

But, taking your program for what it is worth, there are sevearal problems. First, in C++, if you want to access the C header files, you should include them with their C++ names:

#include <cstdio>
#include <cstdlib>

Next, main requires a proper signature:

int main(int, char**) {

Most crucially, you are not allocating enough space for your user's name:

name = (char *)malloc(A_BIG_ENOUGH_NUMBER);

Here, you must allocate enough space that scanf() will not write beyond the end of your buffer. But, you can't possibly know how big that is until afte scanf runs. This catch-22 is the source of "buffer-overflow" bugs. For your test program, since you control the input, it is probably OK to just pick a number bigger than any name you'll ever type. In production code, you must NEVER, EVER, used scanf in this way.

name = (char *)mallocc(40);

By the way, if you are compiling this as C code, you should never cast the return from malloc. If you are compiling this as C++ code, you must always cast the return from malloc.

printf("%c", *name); name++

This line is missing a semicolon. Did you compile this program? In future, please only post code that you have compiled. Please use your computer's cut-and-paste features to post your code, never retype the code by hand.

This line has two other problems. First, you must derefence the name pointer to access the data to which it points. (So, *name instead of name.) Second, you need not dereference name in the second statement on this line, since you do nothing with the resulting pointed-to data. (So, name++ instead of *name++.)

Finally, and most importantly, buy, read, and learn from a good book.

Community
  • 1
  • 1
Robᵩ
  • 163,533
  • 20
  • 239
  • 308
  • Tag has been changed from `C++` to `C`. If it stays `C`, readers should ignore the C++-specific pieces of my answer. – Robᵩ Apr 06 '11 at 15:16
  • Thanks for posting this answer. It's a whole lot more useful to show and explain the differences, rather than just bantering about them in the comments. +1 from me, and definitely don't feel like you should remove it because people do drive-by tag changes. – Cody Gray - on strike Apr 06 '11 at 15:37
0

That's not C++, it's C.

malloc(sizeof(char)) will allocate storage of one char, I expect you wanted more than that.

Also there is no need to allocate dynamically here. Try:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
    char name[256];
    char *p = name;

    printf("Enter string: ");
    scanf("%s", name);

    while (*p != '\0') {
        printf("%c", *p);
        p++;
    }

    return 0;
}
orlp
  • 112,504
  • 36
  • 218
  • 315
Pete
  • 1,241
  • 2
  • 9
  • 21
0

Your program is likely printing junk because you only allocate one byte to your string buffer. When the user enters a string, you will have undefined behavior because the scanf will write past the end of name.

You need to alloc name like this:

char *name = (char *)malloc(MAX_STRING_SIZE, sizeof(char));

Even better to use calloc instead of malloc. Define MAX_STRING_SIZE however you like. A reasonable size depends on the application. In your case, if the users will be entering short strings, then perhaps a reasonable buffer size is 64 bytes, or perhaps 80 or 100.

Also, in your while loop, you can increment and dereference your pointer in one step, like this:

printf("%c", *name++);

If you don't like to be that terse, then you can break them apart, but you don't need to dereference the pointer to increment it.

printf("%c", *name); name++;
Ben Collins
  • 20,538
  • 18
  • 127
  • 187
  • @Cyril Horad: yes. That's always going to be the case. There is no way to allocate a string dynamically for scanf. – Ben Collins Apr 06 '11 at 15:10