Cannot Use Printf!?! (while performing hashing algorithm using mhash) - c

I am using Mhash and I would like to print the length of my blocksize for debugging purposes, but I keep getting an error every time I try to compile
Any suggestions on how I can fix this error?
Here is my code:
#include <mhash.h>
#include <stdio.h>
#include <string.h>
// 0x12e6bc6e68c3b9506e6668db6b7224f894fab073728fc179 (TIGER192) (48)
int main()
{
char password[] = "Jefe";
int keylen = 4;
char data[] = "what do ya want for nothing?";
int datalen = 28;
MHASH td, td2;
unsigned char *mac, *mac2;
int i, j;
td = mhash_hmac_init(MHASH_TIGER192, password, keylen, mhash_get_hash_pblock(MHASH_TIGER192));
mhash(td, data, datalen);
mac = mhash_hmac_end(td);
printf("0x");
for (i = 0; i < mhash_get_block_size(MHASH_TIGER192); i++)
{
printf("%.2x", mac[i]);
}
printf("\n");
// int length = strlen(mac);
// printf(length);
// int length = 5;
// printf(length);
exit(0);
}
I run the program with the following commands:
hb2#hb1:~/Desktop$ gcc -o hashexample hashexample.c -lmhash
hb2#hb1:~/Desktop$ ./hashexample
0x12e6bc6e68c3b9506e6668db6b7224f894fab073728fc179
And it runs successfully, but when I try to print the length of the hashed result, I get the following error!!? Any ideas on why?
// int length = strlen(mac);
// printf(length);
hb2#hb1:~/Desktop$ gcc -o hashexample hashexample.c -lmhash
hashexample.c: In function ‘main’:
hashexample.c:33:2: warning: passing argument 1 of ‘printf’ makes pointer from integer without a cast [enabled by default]
/usr/include/stdio.h:363:12: note: expected ‘const char * __restrict__’ but argument is of type ‘int’
hashexample.c:33:2: warning: format not a string literal and no format arguments [-Wformat-security]
At first, I thought it was because I thought I was using strlen incorrectly?! But even when I try to do a simple printf of an integer, I still get an error:
// int length = 5;
// printf(length);
hb2#hb1:~/Desktop$ gcc -o hashexample hashexample.c -lmhash
hashexample.c: In function ‘main’:
hashexample.c:35:2: warning: passing argument 1 of ‘printf’ makes pointer from integer without a cast [enabled by default]
/usr/include/stdio.h:363:12: note: expected ‘const char * __restrict__’ but argument is of type ‘int’
hashexample.c:35:2: warning: format not a string literal and no format arguments [-Wformat-security]
Thanks for your help in advance!

Check the man page for printf(). The first argument is a const char *. You're passing an int.
That's what the warning says too:
warning: passing argument 1 of ‘printf’ makes pointer from integer without a cast [enabled by default]
You wanted:
printf("%d", length);
You need the format string to specify that an int is going to be printed.

Related

Why is print portion of this program that takes info of 11 cars and prints the model name of red cars not working?

here is the code
#include <stdio.h>
#include <string.h>
int main()
{
int val;
struct info{
char model[50];
int price;
char color[30];
}car[11];
int i;
for(i=0;i<11;i++)
{
printf("Enter model name:\n");
scanf("%s",&car[i].model);
printf("Enter price:\n");
scanf("%d",&car[i].price);
printf("Enter color:\n");
scanf("%s",&car[i].color);
}
printf("\nThe red cars are:\n");
for(i=0;i<11;i++)
{
val=strcmp("red",tolower(car[i].color));
if(0==val)
{
printf("%d. %s\n",i+1,car[i].model);
}
}
return 0;
}
also I tried using gets for string input but it doesn't seem to work.
Here are the warnings:
*main.c:17:17: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char (*)[50]’ [-Wformat=]
scanf("%s",&car[i].model);
main.c:21:17: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char (*)[30]’ [-Wformat=]
scanf("%s",&car[i].color);
main.c:26:34: warning: passing argument 1 of ‘tolower’ makes integer from pointer without a cast [-Wint-conversion]
val=strcmp("red",tolower(car[i].color));
In file included from main.c:4:0:
/usr/include/ctype.h:124:12: note: expected ‘int’ but argument is of type ‘char *’
extern int tolower (int __c) __THROW;
main.c:26:26: warning: passing argument 2 of ‘strcmp’ makes pointer from integer without a cast [-Wint-conversion]
val=strcmp("red",tolower(car[i].color));
In file included from main.c:2:0:
/usr/include/string.h:144:12: note: expected ‘const char *’ but argument is of type ‘int’
extern int strcmp (const char *__s1, const char *__s2)
You posted your compiler output. Good. Let's look at all those errors:
main.c:17:17: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char (*)[50]’
Most of the time, when you call scanf, you need & on the variable being stored, but %s is an exception. (Explanation elsewhere.) Get rid of the &: scanf("%s",car[i].model);
main.c:26:34: warning: passing argument 1 of ‘tolower’ makes integer from pointer without a cast
This is your main problem. Your program as written will never work. tolower expects a single character to convert, but you're passing it a pointer instead. (You're passing it a pointer to the entire string you want to convert.)
/usr/include/ctype.h:124:12: note: expected ‘int’ but argument is of type ‘char *’
This is another message explaining the tolower problem.
main.c:26:26: warning: passing argument 2 of ‘strcmp’ makes pointer from integer without a cast
tolower returns the single character it has converted. But strcmp expects an entire string.
/usr/include/string.h:144:12: note: expected ‘const char *’ but argument is of type ‘int’
This is another message explaining the tolower/strcmp problem.
How to fix this? There is not a standard function (that I can remember) that converts an entire string to lowercase. You'd have to write that yourself. Another option is to use a version of strcmp that compares the strings without regard to case. Two such functions (neither of which is quite standard, however) are strcasecmp and stricmp.
tolower only works with char not string, so use the function on every char of the string.
#include <string.h>
#include <stdio.h>
#include <ctype.h>
int strcicmp(char const *a, char const *b)
{
if (!a && !b)
return 0
else if (!a || !b)
return -1
for (;; a++, b++) {
int d = tolower((unsigned char)*a) - tolower((unsigned char)*b);
if (d != 0 || !*a)
return d;
}
}
int main()
{
int val;
struct info{
char model[50];
int price;
char color[30];
}car[11];
int i;
for(i=0;i<11;i++)
{
printf("Enter model name:\n");
scanf("%s",&car[i].model);
printf("Enter price:\n");
scanf("%d",&car[i].price);
printf("Enter color:\n");
scanf("%s",&car[i].color);
}
printf("\nThe red cars are:\n");
for(i=0;i<11;i++)
{
val=strcicmp(car[i].color, "red");
if(0==val)
{
printf("%d. %s\n",i+1,car[i].model);
}
}
return 0;
}

sscanf multi string scan

i want to capture following string in c with sscanf
"1=Salam Khobi|FC93F8A120F491F3A8=Rial|F191FEA4"
but sscanf only fills &customInput.type and customInputTitle[0] with "Salam Khobi" and other part of string would not scan.
#include <stdio.h>
#include <stdlib.h>
typedef enum {
INPUT_NUMBER = 0,
INPUT_NORMAL = 1,
INPUT_PASSWORD = 2,
INPUT_PAYAMOUNT = 3,
} inputType;
typedef struct {
char * title[2];
char * extra[2];
inputType type;
unsigned minLen:6;
unsigned maxLen:6;
unsigned forceLen:1;
unsigned editable:1;
unsigned char data[100];
} lcdInput;
#define CUSTOM_INPUT_LENGTH 40
static unsigned char customInputTitle[2][CUSTOM_INPUT_LENGTH];
static unsigned char customInputExtra[2][CUSTOM_INPUT_LENGTH];
const char * payload = "1=Salam Khobi|FC93F8A120F491F3A8=Rial|F191FEA4";
#define CUSTOM_INPUT_REGX "%d=%[^|]s|%[^=]s=%[^|]s|%s"
static lcdInput customInput = {
.title = {&customInputTitle[0], &customInputTitle[1]},
.extra = {&customInputExtra[0], &customInputExtra[1]},
.type = INPUT_NORMAL,
.editable = 1,
.forceLen = 0,
};
int main()
{
memset(&customInputTitle, 0, CUSTOM_INPUT_LENGTH << 1);
memset(&customInputExtra, 0, CUSTOM_INPUT_LENGTH << 1);
sscanf(payload, CUSTOM_INPUT_REGX,
&customInput.type,
&customInputTitle[0], &customInputTitle[1],
&customInputExtra[0], &customInputExtra[1]);
return 0;
}
"%d=%[^|]|%[^=]=%[^|]|%s" is the correct format.
The Problem Asked About
After a | character is encountered with the scanset directive %[^|], sscanf() will resume matching with the | character. The next directive should be a literal | to avoid a matching failure. In the original code, with %[^|]s, the s is not a part of the scanset directive, and instead sscanf() seeks to match a literal s in the input. Also, note that maximum width specifiers should always be used with the %s and %[] fscanf() family directives to avoid buffer overflow with malicious or malformed inputs:
"%d=%39[^|]|%39[^=]=%39[^|]|%39s"
Some Other Serious Issues
Always enable warnings when compiling C code; doing so here would have helped you avoid several serious problems. There are a lot of warnings for this code, and most of the problems listed below lead to undefined behavior. I always use at least gcc -std=c11 -Wall -Wextra -Wpedantic, and I have added a sample of gcc output for the original code at the end of the answer.
The posted code is missing #include <string.h> for memset().
The .title and .extra fields of lcdInput should be unsigned char *, since these point to the first elements of unsigned char arrays.
In the initialization of customInput the & operators should be removed. customInput.title and customInput.extra are both expecting pointers to unsigned char (or chars before the above correction). With, e.g. &customInputTitle[0] you have a pointer to an array of CUSTOM_INPUT_LENGTH unsigned chars (or chars before the above correction); this is a type mismatch, and your compiler should complain vociferously (with warnings enabled). Instead, just use:
static lcdInput customInput = {
.title = {customInputTitle[0], customInputTitle[1]},
.extra = {customInputExtra[0], customInputExtra[1]},
.type = INPUT_NORMAL,
.editable = 1,
.forceLen = 0,
};
Here, customInputTitle[0] is an array of CUSTOM_INPUT_LENGTH unsigned chars, which will decay to a pointer to its first element (unsigned char *). Alternatively, you could use &customInputTitle[0][0], &customInputTitle[1][0], etc.
Similarly, you need to remove the ampersands from the customInput arrays in the call to sscanf(). Here you also need to do something about &customInput.type. This is an enum type, and you can't input an enum value. Again, the compiler complains with warnings enabled. Instead, try:
int typeInput;
if (sscanf(payload, CUSTOM_INPUT_REGX,
&typeInput,
customInputTitle[0], customInputTitle[1],
customInputExtra[0], customInputExtra[1]) == 5) {
if (typeInput >= INPUT_NUMBER && typeInput <= INPUT_PAYAMOUNT) {
customInput.type = typeInput;
} else {
/* Handle error */
}
};
Here typeInput is used to collect input, the value returned by sscanf() is checked to verify that the correct number of values was assigned, and the value of typeInput is checked against the value range for inputType. If input is as expected, typeInput is assigned to customInput.type.
The calls to memset() will work, but why obfuscate things with bitshifts? You don't need the & operators here, either, but in this case they are OK. Instead, consider:
memset(customInputTitle, 0, sizeof customInputTitle);
memset(customInputExtra, 0, sizeof customInputExtra);
Here is the corrected code. This compiles with no warnings using gcc -std=c11 -Wall -Wextra -Wpedantic:
#include <stdio.h>
#include <stdlib.h>
#include <string.h> // missing header
typedef enum {
INPUT_NUMBER = 0,
INPUT_NORMAL = 1,
INPUT_PASSWORD = 2,
INPUT_PAYAMOUNT = 3,
} inputType;
typedef struct {
unsigned char * title[2]; // need unsigned char
unsigned char * extra[2];
inputType type;
unsigned minLen:6;
unsigned maxLen:6;
unsigned forceLen:1;
unsigned editable:1;
unsigned char data[100];
} lcdInput;
#define CUSTOM_INPUT_LENGTH 40
static unsigned char customInputTitle[2][CUSTOM_INPUT_LENGTH];
static unsigned char customInputExtra[2][CUSTOM_INPUT_LENGTH];
const char * payload = "1=Salam Khobi|FC93F8A120F491F3A8=Rial|F191FEA4";
// bad format string
#define CUSTOM_INPUT_REGX "%d=%39[^|]|%39[^=]=%39[^|]|%39s"
// & operator not needed
static lcdInput customInput = {
.title = {customInputTitle[0], customInputTitle[1]},
.extra = {customInputExtra[0], customInputExtra[1]},
.type = INPUT_NORMAL,
.editable = 1,
.forceLen = 0,
};
int main(void)
{
// could use improvements
memset(customInputTitle, 0, sizeof customInputTitle);
memset(customInputExtra, 0, sizeof customInputExtra);
// & operators not needed
int typeInput;
if (sscanf(payload, CUSTOM_INPUT_REGX,
&typeInput,
customInputTitle[0], customInputTitle[1],
customInputExtra[0], customInputExtra[1]) == 5) {
if (typeInput >= INPUT_NUMBER && typeInput <= INPUT_PAYAMOUNT) {
customInput.type = typeInput;
} else {
/* Handle error */
}
};
return 0;
}
GCC Output with Warnings
Here are the compiler warnings with gcc -std=c11 -Wall -Wextra -Wpedantic from the original program posted in the question:
bad_program.c:27:19: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
.title = {&customInputTitle[0], &customInputTitle[1]},
^
bad_program.c:27:19: note: (near initialization for ‘customInput.title[0]’)
bad_program.c:27:41: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
.title = {&customInputTitle[0], &customInputTitle[1]},
^
bad_program.c:27:41: note: (near initialization for ‘customInput.title[1]’)
bad_program.c:28:19: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
.extra = {&customInputExtra[0], &customInputExtra[1]},
^
bad_program.c:28:19: note: (near initialization for ‘customInput.extra[0]’)
bad_program.c:28:41: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
.extra = {&customInputExtra[0], &customInputExtra[1]},
^
bad_program.c:28:41: note: (near initialization for ‘customInput.extra[1]’)
bad_program.c: In function ‘main’:
bad_program.c:36:5: warning: implicit declaration of function ‘memset’ [-Wimplicit-function-declaration]
memset(&customInputTitle, 0, CUSTOM_INPUT_LENGTH << 1);
^~~~~~
bad_program.c:36:5: warning: incompatible implicit declaration of built-in function ‘memset’
bad_program.c:36:5: note: include ‘<string.h>’ or provide a declaration of ‘memset’
bad_program.c:25:33: warning: format ‘%d’ expects argument of type ‘int *’, but argument 3 has type ‘inputType * {aka enum <anonymous> *}’ [-Wformat=]
#define CUSTOM_INPUT_REGX "%d=%[^|]s|%[^=]s=%[^|]s|%s"
^
bad_program.c:39:21: note: in expansion of macro ‘CUSTOM_INPUT_REGX’
sscanf(payload, CUSTOM_INPUT_REGX,
^~~~~~~~~~~~~~~~~
bad_program.c:25:33: warning: format ‘%[^|’ expects argument of type ‘char *’, but argument 4 has type ‘unsigned char (*)[40]’ [-Wformat=]
#define CUSTOM_INPUT_REGX "%d=%[^|]s|%[^=]s=%[^|]s|%s"
^
bad_program.c:39:21: note: in expansion of macro ‘CUSTOM_INPUT_REGX’
sscanf(payload, CUSTOM_INPUT_REGX,
^~~~~~~~~~~~~~~~~
bad_program.c:25:33: warning: format ‘%[^=’ expects argument of type ‘char *’, but argument 5 has type ‘unsigned char (*)[40]’ [-Wformat=]
#define CUSTOM_INPUT_REGX "%d=%[^|]s|%[^=]s=%[^|]s|%s"
^
bad_program.c:39:21: note: in expansion of macro ‘CUSTOM_INPUT_REGX’
sscanf(payload, CUSTOM_INPUT_REGX,
^~~~~~~~~~~~~~~~~
bad_program.c:25:33: warning: format ‘%[^|’ expects argument of type ‘char *’, but argument 6 has type ‘unsigned char (*)[40]’ [-Wformat=]
#define CUSTOM_INPUT_REGX "%d=%[^|]s|%[^=]s=%[^|]s|%s"
^
bad_program.c:39:21: note: in expansion of macro ‘CUSTOM_INPUT_REGX’
sscanf(payload, CUSTOM_INPUT_REGX,
^~~~~~~~~~~~~~~~~
bad_program.c:25:33: warning: format ‘%s’ expects argument of type ‘char *’, but argument 7 has type ‘unsigned char (*)[40]’ [-Wformat=]
#define CUSTOM_INPUT_REGX "%d=%[^|]s|%[^=]s=%[^|]s|%s"
^
bad_program.c:39:21: note: in expansion of macro ‘CUSTOM_INPUT_REGX’
sscanf(payload, CUSTOM_INPUT_REGX,
^~~~~~~~~~~~~~~~~

error with running multiple thread with C example

I have found an example of multi thread programming which help to determine the prime numbers for a given integar n.it will also take number of thread as a input from the user.But the problem is when i try to execute it give me some errors which very hard to solve.Can anyone help?I am newbies at coding so any type of help and advice will be greatly appreciated.
#include <stdio.h>
#include <math.h>
#include <pthread.h> // required for threads usage
#define MAX_N 100000000
#define MAX_THREADS 25
int nthreads, n, prime[MAX_N+1], nextbase; // next sieve multiplier to be used
// lock for the shared variable nextbase
pthread_mutex_t nextbaselock = PTHREAD_MUTEX_INITIALIZER;
// ID structs for the threads
pthread_t id[MAX_THREADS];
// "crosses out" all odd multiples of k
void crossout(int k)
{ int i;
for (i = 3; i*k <= n; i += 2) {
prime[i*k] = 0;
}
}
// each thread runs this routine
void *worker(int tn) // tn is the thread number (0,1,...)
{ int lim,base,
work = 0; // amount of work done by this thread
// no need to check multipliers bigger than sqrt(n)
lim = sqrt(n);
do {
pthread_mutex_lock(&nextbaselock);
base = nextbase;
nextbase += 2;
// unlock the lock
pthread_mutex_unlock(&nextbaselock);
if (base <= lim) {
// don't bother crossing out if base known composite
if (prime[base]) {
crossout(base);
work++; // log work done by this thread
}
}
else return work;
} while (1);
}
main(int argc, char **argv)
{ int nprimes, // number of primes found
i,work;
n = atoi(argv[1]);
nthreads = atoi(argv[2]);
for (i = 3; i <= n; i++) {
if (i%2 == 0) prime[i] = 0;
else prime[i] = 1;
}
nextbase = 3;
// get threads started
for (i = 0; i < nthreads; i++) {
pthread_create(&id[i],NULL,worker,i);
}
for (i = 0; i < nthreads; i++) {
pthread_join(id[i],&work);
printf("%d values of base done\n",work);
}
nprimes = 1;
for (i = 3; i <= n; i++)
if (prime[i]) {
nprimes++;
}
printf("the number of primes found was %d\n",nprimes);
}
I have the following error while compiling:
In function ‘worker’:
Primes.c:67:12: warning: return makes pointer from integer without a cast [enabled by default]
else return work;
^
Primes.c: In function ‘main’:
Primes.c:88:7: warning: passing argument 3 of ‘pthread_create’ from incompatible pointer type [enabled by default]
pthread_create(&id[i],NULL,worker,i);
^
In file included from Primes.c:15:0:
/usr/include/pthread.h:244:12: note: expected ‘void * (*)(void *)’ but argument is of type ‘void * (*)(int)’
extern int pthread_create (pthread_t *__restrict __newthread,
^
Primes.c:88:7: warning: passing argument 4 of ‘pthread_create’ makes pointer from integer without a cast [enabled by default]
pthread_create(&id[i],NULL,worker,i);
^
In file included from Primes.c:15:0:
/usr/include/pthread.h:244:12: note: expected ‘void * __restrict__’ but argument is of type ‘int’
using: gcc -c -Wall -Wextra -Wconversion -std=gnu99 %f
where %f is the name of the file being compiled
The compiler output the following messages.
I added some commentary for each message that should point you to how to fix the problem.
compiler warning message:
:28:14: warning: conversion to 'int' from 'double' may alter its' value [-Wconversion]
lim = sqrt(n);
The function: sqrt() returns a 'double' but 'lim' is declared a 'int'
Suggest: cast the returned value to 'int'
lim = (int)sqrt(n);
compiler warning message:
:43:12: warning: return makes pointer from integer without a cast [enbled by default]
else return work;
the return type from the worker() function is void*
always exit the worker() function by:
pthread_exit( &work );
compiler warning message:
:24:18: warning: unused parameter 'tn' [-Wunused-parameter]
means the parameter 'tn' is not used. fix this by inserting in that function the line:
(void)tn;
compiler warning message:
47:1: warning: return type defaults to 'int' [enabled by default]
The signature of the main() function is not correct. without using the environment parameter, (almost never used), there are only 2 valid main() signatures and one optional signature.
use the correct signature for what your program needs.
int main( void )
int main( int argc, char *argv[] )
int main() // optional signature
compiler warning message:
50:4: warning: implicit declaration of function 'atoi' [-Wimplicit-function-declaration]
means the header file: stdlib.h has not been #include'd suggest inserting at top of file:
#include <stdlib.h>
compiler warning message:
61:7: warning: passing argument 3 of 'pthread_create' from incompatible pointer type [enabled by default]
means the third parameter to the function: pthread_create() was not a void pointer. suggest:
pthread_create(&id[i],NULL,worker,(void*)&i);
compiler warning message:
67:7: warning: passing argument 2 of 'pthread_join' from incompatible pointer type [enabled by default]
means the variable 'work' should be declared, in file global space, not in the thread function, as:
void * work;
there are other compiler warning messages output, but the above will eliminate them.
I.E. always start with the first compiler message, fix that, then re-compile. then fix the new first message.
Most of the problems with the syntax of the code could have been avoided by paying attention to the man pages for the system functions that were called in the posted code.
Note: the crossout() functions' logic is not correct. the code needs to start at k+k, continue until k<=n and step by k+=k I.E.
for( int k=i+i; k<(n+1); k+=k )
the code seems to be trying to implement a eratosthenes sieve for prime numbers google for the details.
unless your required to use threads, don't, they will just slow things down due to all the context swapping, etc.
this code logic:
for (i = 3; i <= n; i++)
{
if (i%2 == 0) prime[i] = 0;
else prime[i] = 1;
}
seems to be wrong, for one thing, the array prime[] will be initially all 0 because it is in the file global space. As far as I can tell, that code block is not needed at all.
because the work variable will be in the file global space, suggest an array of
void* work[ nthreads ];
then have the thread function: worker() actually use the passed parameter to select which of the entries in the array to be updating.

Converting string to long using strtol and pointers

My goal is to convert a string such as "A1234" to a long with value 1234. My first step was to just convert "1234" to a long, and that works as expected:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
char* test = "1234";
long val = strtol(test,NULL,10);
char output[20];
sprintf(output,"Value: %Ld",val);
printf("%s\r\n",output);
return 0;
}
Now I am having trouble with pointers and trying to ignore the A at the beginning of the string. I have tried char* test = "A1234"; long val = strtol(test[1],NULL,10); however that crashes the program.
How do I set this up properly to get it pointing to the correct spot?
You are almost right. You need to pass a pointer to strtol, though:
long val = strtol(&test[1], NULL, 10);
or
long val = strtol(test + 1, NULL, 10);
Turning on some compiler warning flags would have told you your problem. For example, from clang (even with no special flags added):
example.c:6:23: warning: incompatible integer to pointer conversion passing
'char' to parameter of type 'const char *'; take the address with &
[-Wint-conversion]
long val = strtol(test[1],NULL,10);
^~~~~~~
&
/usr/include/stdlib.h:181:26: note: passing argument to parameter here
long strtol(const char *, char **, int);
^
1 warning generated.
and from GCC:
example.c: In function ‘main’:
example.c:6: warning: passing argument 1 of ‘strtol’ makes pointer from integer
without a cast
Editorial note: I think you can see from these error messages why beginners are often well-advised to use clang rather than GCC.

listing conditionally an array of strings

I'm trying to list all files and folders in a given directory in C, the following code errors out and i cant figure out whats wrong
#include <sys/types.h>
#include <dirent.h>
#include <regex.h>
#include <stdio.h>
#include <unistd.h>
#include <pwd.h>
enum {
WALK_OK = 0,
WALK_BADPATTERN,
WALK_BADOPEN,
};
int walk_directories(const char *dir, const char *pattern, char* strings[])
{
struct dirent *entry;
regex_t reg;
DIR *d;
int i = 0;
//char array[256][256];
if (regcomp(&reg, pattern, REG_EXTENDED | REG_NOSUB))
return WALK_BADPATTERN;
if (!(d = opendir(dir)))
return WALK_BADOPEN;
while (entry = readdir(d))
if (!regexec(&reg, entry->d_name, 0, NULL, 0) )
//puts(entry->d_name);
strings[i] = (entry->d_name);
i++;
closedir(d);
regfree(&reg);
return WALK_OK;
}
void main()
{
struct passwd *pw = getpwuid(getuid());
char *homedir = pw->pw_dir;
strcat(homedir, "/.themes");
int n = 0;
char *array[256][100];
char *array2[256][100];
walk_directories(homedir, "", array);
for (n = 0; n < 256; n++)
{
//do stuff here later, but just print it for now
printf ("%s\n", array[n]);
}
walk_directories("/usr/share/themes", "", array2);
for (n = 0; n < 256; n++)
{
//do stuff here later, but just print it for now
printf ("%s\n", array2[n]);
}
}
The error at compile time is
test2.c: In function ‘main’:
test2.c:42:2: warning: incompatible implicit declaration of built-in function ‘strcat’ [enabled by default]
test2.c:48:2: warning: passing argument 3 of ‘walk_directories’ from incompatible pointer type [enabled by default]
test2.c:15:5: note: expected ‘char **’ but argument is of type ‘char * (*)[100]’
test2.c:52:6: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char **’ [-Wformat]
test2.c:55:2: warning: passing argument 3 of ‘walk_directories’ from incompatible pointer type [enabled by default]
test2.c:15:5: note: expected ‘char **’ but argument is of type ‘char * (*)[100]’
test2.c:59:6: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char **’ [-Wformat]
If it helps, I've implemented what I want already in python, this is the desired result for C
import os
DATA_DIR = "/usr/share"
def walk_directories(dirs, filter_func):
valid = []
try:
for thdir in dirs:
if os.path.isdir(thdir):
for t in os.listdir(thdir):
if filter_func(os.path.join(thdir, t)):
valid.append(t)
except:
logging.critical("Error parsing directories", exc_info=True)
return valid
def _get_valid_themes():
""" Only shows themes that have variations for gtk+-3 and gtk+-2 """
dirs = ( os.path.join(DATA_DIR, "themes"),
os.path.join(os.path.expanduser("~"), ".themes"))
valid = walk_directories(dirs, lambda d:
os.path.exists(os.path.join(d, "gtk-2.0")) and \
os.path.exists(os.path.join(d, "gtk-3.0")))
return valid
print(_get_valid_themes())
thank you
[EDIT]
thanks for the help, only problem im having now is the printf's all spit out rubbish instead of what i expected, ive tried a few things and the while loop looks like this now
while (entry = readdir(d))
if (!regexec(&reg, entry->d_name, 0, NULL, 0) )
//printf("%s\n",entry->d_name);
strcpy(strings[i], (entry->d_name));
//strings[i] = (entry->d_name);
printf("%i\n",i);
i++;
closedir(d);
the i doesnt get printed properly either, this is all i get from the 3 printf statements
0
Adwaita2
\#
0
Radiance
��
\#
�K��
� `���
����
�
��
�
.N=
�O��
�
�
should mention that if i enable
printf("%s\n",entry->d_name);
then it prints the expected output though
You should include string.h to get the declaration of strcat(3).
In your declaration:
int walk_directories(const char *dir, const char *pattern, char* strings[])
The char *strings[] is just syntactic sugar meaning char **strings. Since you're passing a 2D array, that won't work. It looks to me like you're intending to make two arrays of strings, but that's not what these declarations do:
char *array[256][100];
char *array2[256][100];
You probably don't want the *s there. If you take them off, you can change the signature of walk_directories to this:
int walk_directories(const char *dir, const char *pattern, char strings[][100])
And it should work, with the necessary changes inside your function to match. As a bonus, this change will make your printf calls start working, too.
It looks like you're missing some braces around your while loop body.
The first warning indicates that the compiler cannot figure out what arguments the strcat() function is supposed to take. Since this is a standard C function, this warning means that you are missing a #include directive. Specifically, you need to #include <string.h>. When you fix this, you may find that you get different errors and warnings, so work from there.

Resources