Solved

malloc/array problems

Posted on 2006-10-28
17
278 Views
Last Modified: 2010-05-19
First off, yes this is a homework related question, BUT I only need help with one little piece of my code which I can't seem to make work right.  My understanding of EE rules is that this is acceptable.  So, onto the question:

We're rewriting some of the functions in <string.h> (oh the joys of programming 101 :D) using null-terminated character arrays.  One of the functions I'm trying to write will (hopefully) take a char* (uninitiated), a character, and a length and initiate the array filled with that character.  It compiles fine (using gcc -Wall -pedantic -ansi), but I keep getting run time errors when I try to execute it.

My function is:

int stringFill(char* str, char a, int len){
    int i;

    if((str = malloc(sizeof(char) * (len + 1))) == NULL) return 0;

    for(i=0; i<len; i++) str[i] = a;
    str[len+1] = '\0';

    return 1;
}

I call it like so:

char* string1; stringFill(string1, 'a', 20);
0
Comment
Question by:netsmithcentral
17 Comments
 
LVL 19

Expert Comment

by:BrianGEFF719
Comment Utility
You're losing the memory when the function is returned, the allocated memory has a local scope.

0
 
LVL 19

Accepted Solution

by:
BrianGEFF719 earned 225 total points
Comment Utility
Allocate memory in the calling function:


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

int stringFill(char*, char, int);

void main( void )
{

      char *p;
      int n = 5;

      p = (char *) malloc( sizeof(char) * (n + 1));

      if ( stringFill(p,'a',n) )
            printf("%s",p);


      free(p);
}

int stringFill(char* str, char a, int len)
{
    int i;

    for(i=0; i < len; ++i)
        *(str + i) = a;

     *(str + len) = '\0'; //null terminate

    return 1;
}
0
 
LVL 19

Expert Comment

by:BrianGEFF719
Comment Utility
Also, if you use calloc() there is no need to null terminate:

p = (char *) calloc( (n + 1) , sizeof(char) ); //The char array is already initilized to zero.
0
 
LVL 19

Expert Comment

by:BrianGEFF719
Comment Utility
Here is an example of that:


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


int stringFill(char*, char, int);

void main( void )
{

     char *p;
     int n = 55;

     p = (char *) calloc( (n + 1) , sizeof(char) );

     if ( stringFill(p,'a',n) )
          printf("%s",p);


       printf("\nLen: %d", strlen(p));
     free(p);
}

int stringFill(char* str, char a, int len)
{
    int i;

    for(i=0; i < len; ++i)
       *(str + i) = a;

    return 1;
}
0
 
LVL 19

Expert Comment

by:BrianGEFF719
Comment Utility
Here is an example that demonstrates what is happening:


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

void pTest( char * );

void main( void )
{
      char *p;

      printf("p before = 0x%X\n",p);
      pTest(p);
      printf("p after = 0x%X\n",p);

}

void pTest( char *pC )
{
      pC = (char *) malloc (50);
      printf("p during pTest = 0x%X\n",pC);
}
0
 
LVL 45

Expert Comment

by:sunnycoder
Comment Utility
Not quite Brian ... malloced memory remains in scope until it is freed by calling free.

int stringFill(char* str, char a, int len){
    int i;

    if((str = malloc(sizeof(char) * (len + 1))) == NULL) return 0;

    for(i=0; i<len; i++) str[i] = a;
    str[len+1] = '\0'; ---->>>>>>> For len+1 long array, valid indices are from 0 to len ... len+1 is writing beyond the array

    return 1;
}
0
 
LVL 45

Assisted Solution

by:sunnycoder
sunnycoder earned 225 total points
Comment Utility
and ofcourse!!! You are assigning memory to a local variable ... Brian was on the right track indeed...

>int stringFill(char* str, char a, int len){
Inside the function, str is a local variable ... Any changes made to str will be visible only inside the stringFill function and NOT in the calling function. If you try to dereference the parameter in calling function, you would almost certainly get a crash.

You need to either pass in a char ** so that you can modify the char * variable used in calling function
int stringFill(char** strPtr, char a, int len)

OR

You need to return the new value of str ....
char * stringFill(char* str, char a, int len){
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 19

Expert Comment

by:BrianGEFF719
Comment Utility
>>Not quite Brian ... malloced memory remains in scope until it is freed by calling free.

But in this example you can clearly see that the char pointer p does not contain a valid memory address after the function returns.


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

void pTest( char * );

void main( void )
{
     char *p;

     printf("p before = 0x%X\n",p);
     pTest(p);
     printf("p after = 0x%X\n",p);

}

void pTest( char *pC )
{
     pC = (char *) malloc (50);
     printf("p during pTest = 0x%X\n",pC);
}
0
 
LVL 45

Expert Comment

by:sunnycoder
Comment Utility
That is because char * pC is a local variable ... malloc'ed memory is in scope until it is free()d ... Since it cannot be freed in this case, this would be a memory leak!!!
0
 
LVL 19

Expert Comment

by:BrianGEFF719
Comment Utility
>>int stringFill(char** strPtr, char a, int len)

I didnt even think about that...a pointer to a pointer.
0
 
LVL 2

Expert Comment

by:numansiddique
Comment Utility
The run time error is because of the statement
str[len+1] = '\0';

i agree with BrainGEFF719 , the variable has to be allocated memory before calling the function
0
 
LVL 19

Expert Comment

by:BrianGEFF719
Comment Utility
>>i agree with BrainGEFF719 , the variable has to be allocated memory before calling the function

SunnyCoder has shown that technically it doesnt need to be allocated in the calling function as long as you properly return the pointer and free() the memory in the calling function....I'd still personally allocate in the calling function simply for clarity.
0
 
LVL 12

Author Comment

by:netsmithcentral
Comment Utility
Sorry it took so long to get back to this, my Linux box went down and I didn't have a chance until now to fix it (no Linux = no gcc = no coding for me).  I resolved the initial problem by allocating my memory in main()... I was wondering if you might be able to help me with another problem in the same code (posted the whole thing below).  For some reason, after the first scanf("%c", &srch) (which properly captures whatever character I type), I'm not prompted to enter a character.  Instead, the program always puts a newline character in as if I've typed it!

/*
 * CSC 101 Challenge - Lab 6
 *
 * String functions.  Legth: Return the length
 * of a null terminated string.  Fill: Fills a
 * given string with the given character. Equals
 * checks to see if two strings are the same and
 * prints the result. FindFirst: Finds and returns
 * the position of the first occurrence of a
 * character within a string.
 *
 * @author <<netsmithcentral>>
 *
 */

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

int stringLength(char* str);
void stringFill(char* str, char a, int len);
int stringEquals(char* str1, char* str2);
int stringFindFirst(char* str, char srch);
void stringWrite(char* str);

int main(){
    int cont = 1;

    char srch;
    int rep;

    char* string1; char* string2;
    string1 = (char*) malloc(sizeof(char) * 21);
    string2 = (char*) malloc(sizeof(char) * 21);

    stringFill(string1, 'a', 20); stringFill(string2, 'b', 20);

    printf("String 1 Length: %d\n", stringLength(string1));
    printf("String 2 Length: %d\n", stringLength(string2));
    printf("\n");

    do {
        printf("String 1 ");
          if(stringEquals(string1, string2)) printf("equals");
          else printf("does not equal");
        printf(" String 2.\n\n");

        printf("Enter a search character: "); scanf("%c", &srch);
        printf("Character is at %d in String 1 (-1 means character is not present).\n\n", stringFindFirst(string1, srch));

        printf("Enter position for new character (1 to %d): ", stringLength(string1)); scanf("%d", &rep);
        string1[rep-1] = srch;

        printf("String One's new contents: "); stringWrite(string1);
        printf("\n\n");

        printf("Continue (1 for yes, 0 for no): "); scanf("%d", &cont);
    } while(cont==1);

    free(string1); free(string2);
    return 0;
}

int stringLength(char* str){
    int i = 0;
    while(str[i]!='\0') i++;
    return i;
}

void stringFill(char* str, char a, int len){
    int i;

    for(i=0; i<len; i++) str[i] = a;
    str[len+1] = '\0';
}

int stringEquals(char* str1, char* str2){
    int i;

    if(stringLength(str1)!=stringLength(str2)) return 0;
    for(i=0; i<stringLength(str1); i++){
        if(str1[i]!=str2[i]) return 0;
    } return 1;
}

int stringFindFirst(char* str, char srch){
    int i;
    for(i=0; i<stringLength(str); i++){
        if(str[i]==srch) return i;
    } return -1;
}

void stringWrite(char* str){
    int i;

    for(i=0; i<stringLength(str); i++){
        printf("%c",str[i]);
    }
}
0
 
LVL 19

Expert Comment

by:BrianGEFF719
Comment Utility
You dont need to cast the malloc to a char pointer since malloc returns a charecter pointer by default.
You need to check if malloc was able to allocate the memory eg,

   if (string1 == NULL || string2 == NULL)
   {
    printf("unable to allocate memory");
    exit(1);
   }

Before the end of the while loop trying doing this sometimes scanf does weird things.

       int tmp;
       printf("Continue (1 for yes, 0 for no): "); scanf("%d",&tmp); scanf("%d", &cont);
    } while(cont==1);
0
 
LVL 45

Expert Comment

by:sunnycoder
Comment Utility
>For some reason, after the first scanf("%c", &srch) (which properly captures whatever character I type), I'm not
>prompted to enter a character.  Instead, the program always puts a newline character in as if I've typed it!
Visualize input stream as a buffer ... In response to your first scanf, user inputs a value and presses <enter> key .... This value and \n are both placed in the input buffer ... your first scanf reads the value but leaves behind the \n ... your next scanf, reads this \n from the input buffer ... It does not block for input because it assumes that any value available in this buffer is the input!!

Work around - add additional scanf to clean all input buffer .... scanf also supports regular expressions and other capabilities in format specifiers which you can use to improve the robustness of your program ... It will be worth your time to spend some time reading its man page.

note that fflush (stdin) is undefined.

My prefered way of accepting user input is to use fgets to read in strings, validate them and then convert them to desired format.
0

Featured Post

Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

Join & Write a Comment

Preface I don't like visual development tools that are supposed to write a program for me. Even if it is Xcode and I can use Interface Builder. Yes, it is a perfect tool and has helped me a lot, mainly, in the beginning, when my programs were small…
Windows programmers of the C/C++ variety, how many of you realise that since Window 9x Microsoft has been lying to you about what constitutes Unicode (http://en.wikipedia.org/wiki/Unicode)? They will have you believe that Unicode requires you to use…
The goal of this video is to provide viewers with basic examples to understand and use pointers in the C programming language.
Video by: Grant
The goal of this video is to provide viewers with basic examples to understand and use for-loops in the C programming language.

744 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now