strcpy error

Pages: 123
Which context?
if you want to access ext outside of the if clause you need to declare the variable outside the if clause:
1
2
3
4
5
6
7
8
char * pName = ent->d_name;
char * ext = ...; // Note
if ( strlen(ent->d_name) >2 )
  {
  ext = pName + strlen(ent->d_name) - 3; // Note: 'char *' removed
  }

	
Well, now it works :-) I did not know about this context in if cause. Is the context created by the block {}?
To bring this to finish. Last question to this topic. I want to add the name,filename\n strings to the string which will be written to file. Should I use

char * filedata;
or char filedata[someSize]? As here http://stackoverflow.com/questions/308695/c-string-concatenation
I see they use something like this:

1
2
3
4
5
char str[80];
strcpy (str,"these ");
strcat (str,"strings ");
strcat (str,"are ");
strcat (str,"concatenated.");


But this solution needs to define the size of char array first. What If I don't know how many files will be there so how many strings will be written to the file? I am asking here coz it's just continuation of the actual topic.

Or should I go to the 4th solution?: "Also malloc and realloc are useful if you don't know ahead of time how many strings are being concatenated."
Last edited on
Is the context created by the block {}?
Yes but.

This would also fail:
1
2
if ( strlen(ent->d_name) >2 )
  char * ext = pName + strlen(ent->d_name) - 3;


What If I don't know how many files will be there so how many strings will be written to the file?
It doesn't matter how, it is just important that you provide enough memory to hold all of the data including a terminating 0
Can you use C++ or features or are you required to use C? This is a perfect opportunity for std::string.

If you must use C then you'll need to either malloc()/realloc() or, if you're constructing the string all in one place, make two passes over the pieces to get the length. Using your example:
1
2
3
4
5
6
7
8
9
10
11
12
13
char *str;
size_t len;
len = strlen("these");
len += strlen("strings ");
len += strlen("are ");
len += strlen(concatenated.");

str = malloc(len+1); // +1 for terminating null.

strcpy (str,"these ");
strcat (str,"strings ");
strcat (str,"are ");
strcat (str,"concatenated."); 
Why concatenate in memory? Why not write to file?
dhayden:
I am using C. It is clear to me now. Thanks.
Yet the problem is that I am doing it in loop. I would need to create two loops.

Keskiverto, yes, that sounds better.
Here is my complete code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include "include/types.h"
#include "include/gaussian.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#include <dirent.h>
#include <string.h> // strcmp, strtok
#include <sys/types.h> // mkdir
#include <sys/stat.h> // mkdir

int readFiles(char ** path, FILES * files)
{
    DIR *dir;
    struct dirent *ent;
    int ckey = 0; int c; int count = -1;
    size_t len;

    if ( ( dir = opendir (*path) ) != NULL)
    {
    FILE* f = fopen("kernels.txt", "a");
    if(f==NULL)
        {
        perror("Error opening file.\n");
        }

    while ((ent = readdir (dir)) != NULL)
        {
            if ( ckey<2 && ( strcmp(".",ent->d_name) == 0 ||  strcmp("..",ent->d_name) == 0 )  )
                { ckey++; continue; }

            // backup ent->d_name because chTmp2 is changed by strtok
            len = strlen(ent->d_name);
            // char * dot = strchr( ent->d_name, '.' );
            if ( len >4 )
                {
                char name[64];
                char * pName = ent->d_name;
                char * ext;
                ext = pName + len - 3;
                memcpy( name, ent->d_name, len-3 );
                if ( 0 == strcmp( ".",  name) )
                    {
                    printf("Incorrect kernel source name. File name %s, must not contain dots, but must have .cl extension.\n",ent->d_name);
                    }
                    else
                    {
                    fprintf(f, "%s\n", name);
                    printf (".'%s'\n", ent->d_name);
                    }
                }
                else
                {
                 printf("Incorrect kernel source name. File name %s too short.\n",ent->d_name);
                }
        }
        closedir (dir); close(f);
    }
    else
    {
        /* could not open directory */
        char error [255];
        sprintf(error, "Directory not found: %s", *path);
        perror (error);
        return -1;
    }
return count;
}


This is what I have in kernels.txt
1
2
3
gaussian˙˙˙»‘|ÉĂÁw
gaussian2˙˙»‘|ÉĂÁw
gaussian3˙˙»‘|ÉĂÁw

Last edited on
You forgot to null-terminate your strings.
Sorry but this does not work
fprintf(f, "%s\n\0", name);
How to null-terminate it?
Actual code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include "include/types.h"
#include "include/gaussian.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#include <dirent.h>
#include <string.h> // strcmp, strtok
#include <sys/types.h> // mkdir
#include <sys/stat.h> // mkdir

int makeConfig(char ** path)
{
    char configFile [12] = "kernels.cfg";
    DIR *dir; struct dirent *ent;
    int count = -1;

    if ( ( dir = opendir (*path) ) != NULL)
    {
    char ch;
    FILE* f;
    FILE* f2;
    f = fopen(configFile, "r");
    if( f != NULL ) // if config already exists, backup
        {
        f2 = fopen("kernels.bak", "w");
        while( ( ch = fgetc(f) ) != EOF )
            fputc(ch, f2);
        fclose(f);
        fclose(f2);
        }
    // write new file
    f = fopen(configFile, "w");
        if( f == NULL )
            perror("Cannot write to file kernels.cfg");


    int ckey = 0;
    size_t len;

    while ((ent = readdir (dir)) != NULL)
        {
            if ( ckey<2 && ( strcmp(".",ent->d_name) == 0 ||  strcmp("..",ent->d_name) == 0 )  )
                { ckey++; continue; }

            // backup ent->d_name because chTmp2 is changed by strtok
            len = strlen(ent->d_name);
            // char * dot = strchr( ent->d_name, '.' );
            if ( len >4 )
                {
                char name[64];
                char * pName = ent->d_name;
                char * ext;
                ext = pName + len - 3;
                memcpy( name, ent->d_name, len-3 );
                if ( 0 == strcmp( ".",  name) )
                    {
                    printf("Incorrect kernel source name. File name %s, must not contain dots, but must have .cl extension.\n",ent->d_name);
                    }
                    else
                    {
                    name[len-3]='\0';
                    fprintf(f, "%s\n", name);
                    printf (".'%s'\n", ent->d_name);
                    }
                }
                else
                {
                 printf("Incorrect kernel source name. File name %s too short.\n",ent->d_name);
                }
        }
        closedir (dir); fclose(f);
    }
    else
    {
        /* could not open directory */
        char error [255];
        sprintf(error, "Directory not found: %s", *path);
        perror (error);
        return -1;
    }
return count;
}


int readConfig(char ** path, FILES * files )
{
    char configFile [12] = "kernels.cfg";
    DIR *dir;

    if ( ( dir = opendir (*path) ) == NULL)
        {
            perror("directory of binary kernels not found");
            return -2;
        }
        else
            closedir(dir);

    FILE* f;
    f = fopen(configFile, "r");
    if( f == NULL ) // if config already exists, backup
        {
        perror("Config file kernels.cfg not found. Run the program with -install argument.");
        return -3;
        }

    int ch; int c = 0; int prevc = 0; int count = 0;
    char name[64];
    while ((ch=fgetc(f)) != EOF )
    {
       name[c]=ch;
       c++;
       if (ch == '\n')
           {
           files[count].name=malloc(64);
           files[count].filename=malloc(64);
           // strncpy(files[count].name, name, 64);
           strcpy(files[count].name,name);
           files[count].name[c-prevc-1]='\0'; // remove linefeed \n
           strcpy(files[count].filename,name);
         //  files[count].filename[c-prevc+1]='\0';
           files[count].name[c-prevc+4]='\0';
           strcat(files[count].filename,".bin");
           count++;
           prevc=c;
           }
    }
return count;
}


I will need to create deallocation function yet.
Last edited on
Once again, what is the FILES * files?
Well, I will try to answer your questions from 1st page, sorry I have forgotten about them while I was trying to fix strcpy problems.


What is FILES?
What is files (in the function that calls readFiles)?
How does the caller know how many files were found?


FILES is struct type.
Files is array of 256 structs of type FILES. According to actual code
FILES files[256];
Function returns count of type int. I don't understand how the count is related with the last problem I am solving right now.


FILES * files

In the function header I use * because I use reference to the array &files.
Last edited on
I don't understand how the count is related with the last problem I am solving right now.

When I did ask about count, your function did return EXIT_SUCCESS. That is indeed unrelated now.

FILES is struct type.

That is obvious from code. The real question is who did write it and what is its exact definition?

Files is array of 256 structs
In the function header I use * because I use reference to the array &files.

Please explain the "reference to array". Where does this occur? Code example, please.
Definition of the FILES struct:

1
2
3
4
5
typedef struct  {
  char * name;
  char * filename;
} FILES;
FILES files[256]; // array 


struct of pointers to array chars.

Who did write it? I, of sure.

In the main file, main function I do this call:
The count = readConfig(&path, &files))
&files is reference to array right? Do you want to imply that I should not declare files as FILES* but FILES when using reference?

Edit
Should I allocate memory for files in the main function?
Last edited on
You wrote earlier:
1
2
char str[80];
strcpy( str, "these " );

The strcpy takes char *, but there is no & in front of str on the call. That is correct.

1
2
3
4
T foo[7];

printf( "%p\n", foo );
printf( "%p\n", &foo );

Both lines should print same number, but (unshown) types differ.

You should call count = readConfig( &path, files );

Now, you call malloc(64) to allocate arrays for your strings. You would get almost the same with
1
2
3
4
typedef struct  {
  char name[64];
  char filename[64];
} FILES;

... without worries about deallocation.

If you do continue to use malloc, you could allocate only what you need, not a fixed 64, which may or may not be enough.


Have you tested your makeConfig() with wide variety of "poorly named" directory contents?


What if files were not an array but a linked list?
Please explain this, do I need to allocate the memory to files when I use pointers in struct? I see that I don't need to do that in the case when I use char name[64]; and char filename[64]; That's quite simple. But pls answer the first.
Pages: 123