Your b effort would be a good place to start because it was so near. If you remove the class "table" from tables, I believe the only reason you are reshaping is because of data.frame(table(), which you don't need to do.
Additionally, I would attempt to finish all of the function's processing for a single variable, such as adding headers, labels, etc. In this manner, you may verify that your function does what you want it to do on a single variable before beginning the loop over all variables.
# (b) myfxn — function (x, header = "variable" y = vcat = rownames(y), y, stringsAsFactors = FALSE; y = unclass(table(x, df$cat)) colnames(y) = gsub('d', ", colnames(y));
y) = rbind(c(header, rep(", ncol(y) - 1)), y)
myfxn(df$v1) # vcat low med high # 1 variable # an a 1 0 0 # b b 1 1