1

I checked this but it didn't help - For loop scans one less time in c So, I'm new to programming and I was trying to solve this question from SPOJ (my doubt is general and hence didn't post it in SPOJ forums). http://www.spoj.com/problems/STRHH I made and ran this code in CodeBlocks using GCC where it runs as intended but runs differently when I ran it through Ideone.

#include<stdio.h>
#include<malloc.h>
#include<string.h>
int main()
{
    int n,i,length,j;
    char **ptrarray; //creating a pointer array that holds addresses of the strings  
    fscanf(stdin,"%d",&n);
    ptrarray = (int *)malloc(n*sizeof(int)); //dynamically allocating memory for 'n' strings and storing their addresses in 'ptrarray'
    for (i=0;i<=n;i++)
        ptrarray[i] = (char *)malloc(201); //dynamically allocating memory for the strings
    for (i=0;i<=n;i++)
        fgets(ptrarray[i],201,stdin); //receiving string
    for (i=0;i<=n;i++)
    {
        length=strlen(ptrarray[i])-1; //string length
        for (j=0;j<(length)/2;j+=2) //obtain every other character up to half of the string length
            printf("%c",ptrarray[i][j]);
        printf("\n");
    }
    return 0;
}

Input:

4
your 
progress 
is 
noticeable

Expected Output:

y
po
i
ntc

So, I get the expected output when I run it in Codeblocks but when running it on ideone (and submitting it on SPOJ), the printf loop only runs thrice instead of 4 times and the output I get is:

y
po
i

My question is why I'm not getting the fourth "ntc" in ideone and why is it not being accepted?

Edit: Changed "200" to "201" bytes, used fscanf instead of scanf, removed fflush and updated loop condition. So, I get the required answer if I change loop condition from '

1 Answers1

4

This:

char **ptrarray; //creating a pointer array that holds addresses of the strings  
scanf("%d",&n);
ptrarray = (int *)malloc(n*sizeof(int)); //dynamically allocating memory for 'n' strings and storing their addresses in 'ptrarray'

Makes no sense; you're allocating space for n integers, but assigning the result to a pointer to a pointer (neither of which is the same size as an integer, in general).

The allocation should be:

ptrarray = malloc(n * sizeof *ptrarray);

This will allocate n times the size of whatever ptrarray points at, i.e. sizeof (char *), but without repeating any type names.

This is a quite general and much safer pattern, worth learning.

As mentioned in the comment, don't fflush(stdin);, it's undefined behavior.

unwind
  • 391,730
  • 64
  • 469
  • 606
  • Additional note, `ptrarray` is not an array, should be rename with a proper name. – Stargateur Dec 14 '17 at 15:47
  • @unwind sizeof *ptrarray is equivalent to sizeof char * right? And char * is a pointer to a character. So it will hold an unsigned integer. By that logic, isn't sizeof(int) the same as sizeof(char *) and by extension sizeof(*ptrarray)? – Naishadh Vora Dec 14 '17 at 19:47
  • @NaishadhVora "And char * is a pointer to a character. So it will hold an unsigned integer." --> No. Pointer sizes and `int` size are not correlated. – chux - Reinstate Monica Dec 14 '17 at 19:53
  • @chux I was given to understand that char * would hold the address of a character. Wouldn't that be in the form of a unsigned integer? Sorry, I'm pretty new at this! – Naishadh Vora Dec 14 '17 at 19:54
  • @NaishadhVora "char * would hold the address of a character" Yes that is true. "Wouldn't that be in the form of a unsigned integer?" Maybe, maybe not - it is an implementation detail. More importantly: code should not care about that. – chux - Reinstate Monica Dec 14 '17 at 19:56
  • @chux Oh now I get it! Thanks! But changing sizeof(int) to sizeof(*ptrarray) still only gives the 3 output. What needs to be changed to get "ntc" as well? – Naishadh Vora Dec 14 '17 at 20:05
  • @NaishadhVora Hint: What causes `scanf("%d",&n);` to stop taking input? `fgets()` then reads from that character. Moral of the story - avoid `scanf()`. – chux - Reinstate Monica Dec 14 '17 at 20:29
  • @chux I used fscanf(stdin,"%d",&n); instead but it didn't help. The fgets() loops still only runs thrice. What would you suggest should be used? And the output still doesn't show "ntc" – Naishadh Vora Dec 15 '17 at 07:20
  • So, I get the required answer if I change loop condition from " – Naishadh Vora Dec 15 '17 at 07:47
  • @NaishadhVora "why this was necessary" is answered by the question you avoided: "What causes scanf("%d",&n); to stop taking input?" The `'\n'` is not consumed. – chux - Reinstate Monica Dec 15 '17 at 13:22
  • @chux Got it! Thanks! Also, is there any way to prevent fgets() from taking '\n' as input? – Naishadh Vora Dec 15 '17 at 13:29
  • @chux Got it! Thanks! Also, is there any way to prevent fgets() from using '\n' as input? – Naishadh Vora Dec 15 '17 at 13:30
  • The point of `fgets()` is to read up to and including `'\n'`. – chux - Reinstate Monica Dec 15 '17 at 13:34
  • The dirty solution is to `scanf("%d%*c",&n);` to consume the character after the number (hopefully `'\n'`). The robust solution: `char b[80]; fget(b, sizeof b, stdin); sscanf(b, "%d%*c",&n);` with some error checking. – chux - Reinstate Monica Dec 15 '17 at 13:36